Repository: QwikDev/qwik Branch: main Commit: 220105b5d4e7 Files: 2456 Total size: 8.1 MB Directory structure: gitextract_s2quyj30/ ├── .all-contributorsrc ├── .changeset/ │ ├── breezy-items-relax.md │ ├── changelog-github-custom.cjs │ ├── changelog-github-custom.ts │ ├── config.json │ ├── deno-production-builds.md │ ├── eager-sides-sit.md │ ├── fix-virtual-css-dev-ssr.md │ ├── late-parrots-open.md │ ├── shaky-ends-help.md │ ├── small-candies-train.md │ └── smooth-ends-count.md ├── .devcontainer/ │ ├── Dockerfile │ └── devcontainer.json ├── .dockerignore ├── .envrc ├── .gitattributes ├── .github/ │ ├── CODEOWNERS │ ├── ISSUE_TEMPLATE/ │ │ ├── bug.yaml │ │ ├── config.yml │ │ └── docs_suggestion.yml │ ├── PULL_REQUEST_TEMPLATE.md │ └── workflows/ │ ├── ai-issue-triage.yml │ ├── auto-assign-core-team.yml │ ├── bench.yml.disabled │ ├── ci.yml │ ├── closing-issues.yml │ ├── deploy-docs.yml │ └── labeling-issues.yml ├── .gitignore ├── .node-version ├── .nvmrc ├── .prettierignore ├── .prettierrc.json ├── .vscode/ │ ├── extensions.json │ ├── launch.json │ ├── qwik.code-snippets │ └── settings.json ├── @types/ │ ├── bun.d.ts │ └── deno.d.ts ├── AGENTS.md ├── CLAUDE.md ├── CODE_OF_CONDUCT.md ├── CONTINUOUS_BUILD.md ├── CONTRIBUTING.md ├── Cargo.toml ├── Dockerfile ├── GOVERNANCE.md ├── LICENSE ├── Makefile ├── README.md ├── SECURITY.md ├── contributing/ │ └── TRIAGE.md ├── cspell.json ├── e2e/ │ ├── adapters-e2e/ │ │ ├── .gitignore │ │ ├── adapters/ │ │ │ └── express/ │ │ │ └── vite.config.ts │ │ ├── package.json │ │ ├── playwright.config.ts │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── click-me/ │ │ │ │ │ └── click-me.tsx │ │ │ │ └── router-head/ │ │ │ │ └── router-head.tsx │ │ │ ├── entry.dev.tsx │ │ │ ├── entry.express.tsx │ │ │ ├── entry.preview.tsx │ │ │ ├── entry.ssr.tsx │ │ │ ├── root.tsx │ │ │ └── routes/ │ │ │ ├── index.tsx │ │ │ ├── layout.tsx │ │ │ ├── profile/ │ │ │ │ └── index.tsx │ │ │ └── service-worker.ts │ │ ├── tests/ │ │ │ └── express.spec.ts │ │ ├── tsconfig.json │ │ └── vite.config.ts │ ├── docs-e2e/ │ │ ├── .gitignore │ │ ├── package.json │ │ ├── playwright.config.ts │ │ └── tests/ │ │ ├── Docs/ │ │ │ ├── advanced-pages-load.spec.ts │ │ │ ├── community-pages.load.spec.ts │ │ │ ├── concepts-pages-laod.spec.ts │ │ │ ├── cookbook-pages-load.spec.ts │ │ │ ├── deployments-pages-load.spec.ts │ │ │ ├── docs-components-pages-load.spec.ts │ │ │ ├── guides-pages-load.spec.ts │ │ │ ├── integrations-pages-load.spec.ts │ │ │ ├── navBarOnMobile.spec.ts │ │ │ ├── pages-load-test.spec.ts │ │ │ ├── qwik-city-pages-load.spec.ts │ │ │ ├── qwik-labs-pages-load.spec.ts │ │ │ ├── reference-pages-load.spec.ts │ │ │ └── searchBar.spec.ts │ │ ├── Ecosystem/ │ │ │ └── ecosystem-pages-load.spec.ts │ │ └── Sandbox/ │ │ ├── autoComplete.spec.ts │ │ ├── clockVisible.spec.ts │ │ ├── counter.spec.ts │ │ ├── partial.spec.ts │ │ ├── routing.spec.ts │ │ ├── sandbox.spec.ts │ │ └── usetask.spec.ts │ ├── qwik-cli-e2e/ │ │ ├── README.md │ │ ├── package.json │ │ ├── tests/ │ │ │ └── serve.spec.ts │ │ ├── tsconfig.json │ │ ├── utils/ │ │ │ ├── index.ts │ │ │ └── setup.ts │ │ └── vite.config.ts │ └── qwik-react-e2e/ │ ├── .gitignore │ ├── adapters/ │ │ └── express/ │ │ └── vite.config.ts │ ├── package.json │ ├── playwright.config.ts │ ├── src/ │ │ ├── components/ │ │ │ ├── counter/ │ │ │ │ └── index.tsx │ │ │ └── router-head/ │ │ │ └── router-head.tsx │ │ ├── entry.dev.tsx │ │ ├── entry.express.tsx │ │ ├── entry.preview.tsx │ │ ├── entry.ssr.tsx │ │ ├── root.tsx │ │ └── routes/ │ │ ├── index.tsx │ │ ├── layout.tsx │ │ └── react/ │ │ └── index.tsx │ ├── tests/ │ │ └── express.spec.ts │ ├── tsconfig.json │ └── vite.config.ts ├── eslint.config.js ├── flake.nix ├── package.json ├── packages/ │ ├── create-qwik/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── create-qwik.cjs │ │ ├── index.ts │ │ ├── package.json │ │ └── src/ │ │ ├── create-app-facade.ts │ │ ├── create-app.ts │ │ ├── helpers/ │ │ │ ├── clearDir.ts │ │ │ ├── installDepsCli.ts │ │ │ ├── jokes.json │ │ │ ├── jokes.ts │ │ │ ├── logAppCreated.ts │ │ │ ├── resolveRelativeDir.ts │ │ │ └── templateManager.ts │ │ ├── run-create-cli.ts │ │ ├── run-create-interactive-cli.ts │ │ └── types.ts │ ├── docs/ │ │ ├── .gitignore │ │ ├── .node-version │ │ ├── .npmrc │ │ ├── .prettierignore │ │ ├── README.md │ │ ├── adapters/ │ │ │ └── cloudflare-pages/ │ │ │ └── vite.config.mts │ │ ├── algolia.json │ │ ├── check-qwik-build.ts │ │ ├── codesandbox.sync.ts │ │ ├── contributors.ts │ │ ├── global.d.ts │ │ ├── package.json │ │ ├── public/ │ │ │ ├── _headers │ │ │ ├── _redirects │ │ │ ├── _routes.json │ │ │ ├── builder/ │ │ │ │ ├── 115b3b36cedd455196b06f5d33a57ac1 │ │ │ │ ├── 281010f5f1694d8bbf399c8ffe4a1d87 │ │ │ │ ├── 2e03c5254011431fb48466e2e1eb08a2 │ │ │ │ ├── 31df46c5b87744fd8a4347d3a17a47a6 │ │ │ │ ├── 329d8065fc13497e8588c3f03df1f49a │ │ │ │ ├── 42067d8b20a74503a497b72f53665b13 │ │ │ │ ├── 4b7b38f10af348c4b8b2809db664c11f │ │ │ │ ├── 52a1f6b5be704dc9b5080d64acfb9ccf │ │ │ │ ├── 644d27976d234ec9b453501c209bffa3 │ │ │ │ ├── 67d3020da766431cb03fbe794e808be8 │ │ │ │ ├── 80ac5f7793b545499d3d8944ff7ff3f3 │ │ │ │ ├── 8f2ccdcaa669452c85c1b74d2c162a3d │ │ │ │ ├── 91320f7f7e764055b4f1722189241838 │ │ │ │ ├── a27427ee8bac4f509053ca6de1a4553a │ │ │ │ ├── aee5f202a90e4659bbc6374aed3ff138 │ │ │ │ ├── b6a806948cef4946aec55fa4fa9173cd │ │ │ │ ├── ba922b4f3134477580035b01dc804a26 │ │ │ │ ├── bef8f28d07034b91a89f4518e06314da │ │ │ │ ├── c32d1ef92781491a86dcdc8859b193d2 │ │ │ │ ├── ccfe1879407845b8906b870fc4ef607d │ │ │ │ ├── d1768a789936434a905973daf12768f6 │ │ │ │ ├── d805a18ff6d0410f92603fb691c87349 │ │ │ │ ├── eee9dff8ee0e4b4e9ad1a8825643030c │ │ │ │ ├── efcf8d0391fe4d8bb7e557e6d295a2b2 │ │ │ │ ├── fdc08238cb4d49d48d3a468308992e15 │ │ │ │ ├── high.js │ │ │ │ ├── med.js │ │ │ │ └── qwik-0.100.0.js │ │ │ ├── docs/ │ │ │ │ └── qwikcity/ │ │ │ │ └── README.md │ │ │ └── robots.txt │ │ ├── scripts/ │ │ │ ├── pages.json │ │ │ └── showcase.ts │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── code-block/ │ │ │ │ │ ├── code-block.css │ │ │ │ │ ├── code-block.tsx │ │ │ │ │ └── prismjs.ts │ │ │ │ ├── code-sandbox/ │ │ │ │ │ ├── index.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── content-nav/ │ │ │ │ │ ├── content-nav.css │ │ │ │ │ └── content-nav.tsx │ │ │ │ ├── contributors/ │ │ │ │ │ ├── contributors.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── copy-code/ │ │ │ │ │ ├── copy-code-block.tsx │ │ │ │ │ └── copy-code.css │ │ │ │ ├── docsearch/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── algolia-logo.tsx │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── context.ts │ │ │ │ │ ├── doc-search-button.tsx │ │ │ │ │ ├── doc-search-modal.tsx │ │ │ │ │ ├── doc-search.css │ │ │ │ │ ├── doc-search.tsx │ │ │ │ │ ├── error-screen.tsx │ │ │ │ │ ├── handleSearch.ts │ │ │ │ │ ├── hit.tsx │ │ │ │ │ ├── icons/ │ │ │ │ │ │ ├── ControlKeyIcon.tsx │ │ │ │ │ │ ├── ErrorIcon.tsx │ │ │ │ │ │ ├── LoadingIcon.tsx │ │ │ │ │ │ ├── NoResultsIcon.tsx │ │ │ │ │ │ ├── RecentIcon.tsx │ │ │ │ │ │ ├── ResetIcon.tsx │ │ │ │ │ │ ├── SearchIcon.tsx │ │ │ │ │ │ ├── SelectIcon.tsx │ │ │ │ │ │ ├── SourceIcon.tsx │ │ │ │ │ │ └── StarIcon.tsx │ │ │ │ │ ├── no-results-screen.tsx │ │ │ │ │ ├── result.tsx │ │ │ │ │ ├── results-screen.tsx │ │ │ │ │ ├── screen-state.tsx │ │ │ │ │ ├── search-box.tsx │ │ │ │ │ ├── snippet.tsx │ │ │ │ │ ├── start-screen.tsx │ │ │ │ │ ├── stored-searches.ts │ │ │ │ │ ├── types/ │ │ │ │ │ │ ├── DocSearchHit.ts │ │ │ │ │ │ ├── InternalDocSearchHit.ts │ │ │ │ │ │ ├── StoredDocSearchHit.ts │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── useTouchEvents.ts │ │ │ │ │ ├── useTrapFocus.ts │ │ │ │ │ ├── utils/ │ │ │ │ │ │ ├── groupBy.ts │ │ │ │ │ │ ├── identity.ts │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ ├── isSamsung.ts │ │ │ │ │ │ ├── noop.ts │ │ │ │ │ │ ├── removeHighlightTags.ts │ │ │ │ │ │ └── stalledControl.ts │ │ │ │ │ └── version.ts │ │ │ │ ├── footer/ │ │ │ │ │ ├── footer.css │ │ │ │ │ └── footer.tsx │ │ │ │ ├── header/ │ │ │ │ │ ├── header.css │ │ │ │ │ └── header.tsx │ │ │ │ ├── on-this-page/ │ │ │ │ │ ├── on-this-page.css │ │ │ │ │ └── on-this-page.tsx │ │ │ │ ├── package-manager-tabs/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── panel-toggle/ │ │ │ │ │ ├── panel-toggle.css │ │ │ │ │ └── panel-toggle.tsx │ │ │ │ ├── qwik-gpt/ │ │ │ │ │ ├── gpt.md │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── search.tsx │ │ │ │ │ └── streaming-gpt.ts │ │ │ │ ├── real-metrics-optimization/ │ │ │ │ │ └── real-metrics-optimization.tsx │ │ │ │ ├── router-head/ │ │ │ │ │ ├── router-head.tsx │ │ │ │ │ ├── social.tsx │ │ │ │ │ └── vendor.tsx │ │ │ │ ├── sidebar/ │ │ │ │ │ ├── sidebar.css │ │ │ │ │ └── sidebar.tsx │ │ │ │ ├── sponsors/ │ │ │ │ │ └── sponsors.tsx │ │ │ │ ├── svgs/ │ │ │ │ │ ├── alert-icon.tsx │ │ │ │ │ ├── bluesky-logo.tsx │ │ │ │ │ ├── builder-logo.tsx │ │ │ │ │ ├── chat-icon.tsx │ │ │ │ │ ├── close-icon.tsx │ │ │ │ │ ├── copy-code-icon.tsx │ │ │ │ │ ├── discord-logo.tsx │ │ │ │ │ ├── edit-icon.tsx │ │ │ │ │ ├── github-logo.tsx │ │ │ │ │ ├── more-icon.tsx │ │ │ │ │ ├── qwik-logo.tsx │ │ │ │ │ └── twitter-logo.tsx │ │ │ │ └── theme-toggle/ │ │ │ │ ├── Brilliance.tsx │ │ │ │ ├── Moon.tsx │ │ │ │ ├── README.md │ │ │ │ ├── Sun.tsx │ │ │ │ ├── load-theme.js │ │ │ │ ├── theme-script.tsx │ │ │ │ ├── theme-toggle.css │ │ │ │ └── theme-toggle.tsx │ │ │ ├── constants.ts │ │ │ ├── context.ts │ │ │ ├── empty.ts │ │ │ ├── entry.cloudflare-pages.tsx │ │ │ ├── entry.dev.tsx │ │ │ ├── entry.preview.tsx │ │ │ ├── entry.ssr.tsx │ │ │ ├── global.css │ │ │ ├── repl/ │ │ │ │ ├── README.md │ │ │ │ ├── bundler/ │ │ │ │ │ ├── bundled.tsx │ │ │ │ │ ├── bundler-worker.ts │ │ │ │ │ ├── client-events-listener.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── repl-ssr-worker.ts │ │ │ │ │ └── rollup-plugins.ts │ │ │ │ ├── register-repl-sw.ts │ │ │ │ ├── repl-constants.ts │ │ │ │ ├── repl-instance.ts │ │ │ │ ├── repl-sw.ts │ │ │ │ ├── types.ts │ │ │ │ └── ui/ │ │ │ │ ├── editor.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── monaco.tsx │ │ │ │ ├── repl-commands.tsx │ │ │ │ ├── repl-console.tsx │ │ │ │ ├── repl-detail-panel.tsx │ │ │ │ ├── repl-input-panel.tsx │ │ │ │ ├── repl-options.tsx │ │ │ │ ├── repl-output-modules.tsx │ │ │ │ ├── repl-output-panel.tsx │ │ │ │ ├── repl-output-segments.tsx │ │ │ │ ├── repl-output-update.ts │ │ │ │ ├── repl-share-url.ts │ │ │ │ ├── repl-share-url.unit.ts │ │ │ │ ├── repl-tab-button.tsx │ │ │ │ ├── repl-tab-buttons.tsx │ │ │ │ ├── repl-version.ts │ │ │ │ └── repl.css │ │ │ ├── root.tsx │ │ │ ├── routes/ │ │ │ │ ├── (blog)/ │ │ │ │ │ ├── blog/ │ │ │ │ │ │ ├── (articles)/ │ │ │ │ │ │ │ ├── astro-qwik/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── fontless/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── framer-motion-qwik/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── introducing-qwik-starters/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── module-extraction-the-silent-web-revolution/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qwik-1-14-preloader/ │ │ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ │ │ ├── modulepreload-no-delay-demo-crop.webm │ │ │ │ │ │ │ │ └── service-worker-delay-demo-crop.webm │ │ │ │ │ │ │ ├── qwik-1-2-performance-autopilot/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qwik-2-coming-soon/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qwik-and-qwik-city-have-reached-beta/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qwik-city-routing/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qwik-city-server-functions/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qwik-next-leap/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qwik-rc-milestone/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qwik-tasks/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qwik-v1/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── resumable-react-how-to-use-react-inside-qwik/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── the-qase-for-qwik-love-at-first-tti/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ └── type-safe-forms-in-qwik/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── components/ │ │ │ │ │ │ │ ├── articles-grid.tsx │ │ │ │ │ │ │ ├── featured-article.tsx │ │ │ │ │ │ │ └── mdx/ │ │ │ │ │ │ │ ├── article-block.tsx │ │ │ │ │ │ │ ├── article-hero.tsx │ │ │ │ │ │ │ └── discord-link.tsx │ │ │ │ │ │ ├── icons/ │ │ │ │ │ │ │ ├── clock-icon.tsx │ │ │ │ │ │ │ └── send-icon.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── data.ts │ │ │ │ │ └── layout.tsx │ │ │ │ ├── (ecosystem)/ │ │ │ │ │ ├── ecosystem/ │ │ │ │ │ │ ├── ecosystem-menu.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── menu-items.tsx │ │ │ │ │ │ ├── mobile-ecosystem-menu.tsx │ │ │ │ │ │ └── qwik-plus-logo.tsx │ │ │ │ │ ├── ecosystem.css │ │ │ │ │ ├── ecosystem.json │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── media/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── media.css │ │ │ │ │ └── showcase/ │ │ │ │ │ ├── generated-pages.json │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── styles.css │ │ │ │ ├── 404/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── 404.css │ │ │ │ ├── 404.tsx │ │ │ │ ├── api/ │ │ │ │ │ ├── api.css │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── qwik/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-middleware-aws-lambda/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-middleware-azure-swa/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-middleware-cloudflare-pages/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-middleware-firebase/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-middleware-netlify-edge/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-middleware-node/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-middleware-request-handler/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-middleware-vercel-edge/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-static/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-vite-azure-swa/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-vite-bun-server/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-vite-cloud-run/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-vite-cloudflare-pages/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-vite-netlify-edge/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-vite-node-server/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-vite-static/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-city-vite-vercel/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-optimizer/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── qwik-server/ │ │ │ │ │ │ ├── api.json │ │ │ │ │ │ └── index.mdx │ │ │ │ │ └── qwik-testing/ │ │ │ │ │ ├── api.json │ │ │ │ │ └── index.mdx │ │ │ │ ├── community/ │ │ │ │ │ ├── groups/ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── menu.md │ │ │ │ │ ├── projects/ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ └── values/ │ │ │ │ │ └── index.mdx │ │ │ │ ├── demo/ │ │ │ │ │ ├── .prettierrc.json │ │ │ │ │ ├── api/ │ │ │ │ │ │ └── add/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── component/ │ │ │ │ │ │ ├── child/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── inline-child/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── lazy/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── primitive-props/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── props/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── ref/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── reference-props/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── relativeUrl/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── simple/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── useId/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── context/ │ │ │ │ │ │ └── minimal/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── cookbook/ │ │ │ │ │ │ ├── algolia-search/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── combine-request-handlers/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── debouncer/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── detect-img-tag-onload/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── drag&drop/ │ │ │ │ │ │ │ ├── advanced/ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── basic/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── glob-import/ │ │ │ │ │ │ │ ├── examples/ │ │ │ │ │ │ │ │ ├── example1.tsx │ │ │ │ │ │ │ │ ├── example2.tsx │ │ │ │ │ │ │ │ └── example3.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── leaflet-map/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── mediaController/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── nav-link/ │ │ │ │ │ │ │ ├── example/ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── portal/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ │ ├── popup-example.css │ │ │ │ │ │ │ ├── portal-provider.css │ │ │ │ │ │ │ └── portal-provider.tsx │ │ │ │ │ │ ├── re-exporting-loaders/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ ├── shared/ │ │ │ │ │ │ │ │ └── loaders.ts │ │ │ │ │ │ │ └── third-party/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── third-party-library.tsx │ │ │ │ │ │ ├── streaming-deferred-loaders/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── sync-event/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── demo-reset.css │ │ │ │ │ ├── events/ │ │ │ │ │ │ ├── custom-event/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── extracted-handler/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── global-events/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── mouse-position/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── preventdefault/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── synchronous/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── target/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── use-on/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── use-on-window/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── getting-started/ │ │ │ │ │ │ ├── 01-route/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── 02-loading-data/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── 03-posting-data/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── 04-state/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── 05-tasks/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── 06-styling/ │ │ │ │ │ │ ├── index.css │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── integration/ │ │ │ │ │ │ ├── img/ │ │ │ │ │ │ │ ├── qwik-image/ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── unpic/ │ │ │ │ │ │ │ └── simple/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── modular-forms/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── qwikcity/ │ │ │ │ │ │ └── middleware/ │ │ │ │ │ │ ├── basePathname/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── cacheControl/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── component/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── cookie/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── env/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── error/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── exit/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── getWritableStream/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── headerSent/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── headers/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── html/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── json/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ ├── locale/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── method/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── next/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── params/ │ │ │ │ │ │ │ └── [myId]/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── parseBody/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── platform/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── proxy/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── query/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── redirect/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── request/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── send/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── sharedMap/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── status/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── text/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── throw/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── url/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── react/ │ │ │ │ │ │ ├── children/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── react.tsx │ │ │ │ │ │ ├── counter-simple/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── react.tsx │ │ │ │ │ │ ├── counter-simple-hover/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── react.tsx │ │ │ │ │ │ ├── counter-two-islands/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── react.tsx │ │ │ │ │ │ ├── counter-two-islands-host/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── react.tsx │ │ │ │ │ │ ├── hello-world/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── react.tsx │ │ │ │ │ │ ├── mui/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── react.tsx │ │ │ │ │ │ └── slider/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── react.tsx │ │ │ │ │ ├── resumability/ │ │ │ │ │ │ ├── component.css │ │ │ │ │ │ ├── component.tsx │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── slot/ │ │ │ │ │ │ ├── advanced/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── basic/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── named/ │ │ │ │ │ │ │ ├── index.css │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── unprojected/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── state/ │ │ │ │ │ │ ├── computed/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── counter/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── counter-signal/ │ │ │ │ │ │ │ ├── .prettierrc.json │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── counter-store/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── counter-store-deep/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── counter-store-no-track/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── no-serialize/ │ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ │ └── monaco.tsx │ │ │ │ │ │ ├── passing-context/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── passing-props/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── resource/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── resource-agify/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── resource-joke/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── tasks/ │ │ │ │ │ │ ├── cleanup/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── track/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── track-fn/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── track-server-guard/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── use-task/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── use-visible-task/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── use-visible-task-eager/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── tsconfig.json │ │ │ │ ├── devtools/ │ │ │ │ │ └── json/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── docs/ │ │ │ │ │ ├── (qwik)/ │ │ │ │ │ │ ├── advanced/ │ │ │ │ │ │ │ ├── containers/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── custom-build-dir/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── dollar/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── eslint/ │ │ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ │ │ └── styles.css │ │ │ │ │ │ │ ├── library/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── modules-prefetching/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── optimizer/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qrl/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qwikloader/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ └── vite/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── concepts/ │ │ │ │ │ │ │ ├── progressive/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── reactivity/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── resumable/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ └── think-qwik/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── core/ │ │ │ │ │ │ │ ├── context/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── events/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── overview/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── rendering/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── slots/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── state/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── styles/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ └── tasks/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── deprecated-features/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── faq/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── getting-started/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── (qwikcity)/ │ │ │ │ │ │ ├── action/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── advanced/ │ │ │ │ │ │ │ ├── complex-forms/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── content-security-policy/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── menu/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── plugins/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── request-handling/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── routing/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── sitemaps/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── speculative-module-fetching/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ └── static-assets/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── api/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── caching/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── endpoints/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── error-handling/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── guides/ │ │ │ │ │ │ │ ├── best-practices/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── bundle/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── capacitor/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── debugging/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── deploy/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── env-variables/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── mdx/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── qwik-nutshell/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── react-cheat-sheet/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── redirects/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── rewrites/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ ├── serialization/ │ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ │ └── static-site-generation/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── html-attributes/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── layout/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── middleware/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── pages/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── project-structure/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── qwikcity/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── qwikcity-deprecated-features/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── re-exporting-loaders/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── route-loader/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── routing/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── server$/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── troubleshooting/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ └── validator/ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── cookbook/ │ │ │ │ │ │ ├── algolia-search/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── combine-request-handlers/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── debouncer/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── detect-img-tag-onload/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── drag&drop/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── fonts/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── glob-import/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── mediaController/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── nav-link/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── node-docker-deploy/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── portals/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── streaming-deferred-loaders/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── sync-events/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── theme-management/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ └── view-transition/ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── deployments/ │ │ │ │ │ │ ├── aws-lambda/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── azion/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── azure-swa/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── bun/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── cloudflare-pages/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── cloudflare-workers/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── delete-layout.tsx │ │ │ │ │ │ ├── deno/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── firebase/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── gcp-cloud-run/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── github-pages/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── netlify-edge/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── node/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── self-hosting/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── static/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ └── vercel-edge/ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── docs.css │ │ │ │ │ ├── integrations/ │ │ │ │ │ │ ├── astro/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── authjs/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── bootstrap/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── builderio/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── cypress/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── delete-layout.tsx │ │ │ │ │ │ ├── drizzle/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── i18n/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── icons/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── image-optimization/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── integrations-list.tsx │ │ │ │ │ │ ├── leaflet-map/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── modular-forms/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── nx/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── og-img/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── orama/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── panda-css/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── partytown/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── playwright/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── postcss/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── prisma/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── react/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── storybook/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── styled-vanilla-extract/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── supabase/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── tailwind/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── tailwind-v3/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── tauri/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── turso/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ └── vitest/ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── labs/ │ │ │ │ │ │ ├── devtools/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── insights/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ ├── typed-routes/ │ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ │ └── usePreventNavigate/ │ │ │ │ │ │ └── index.mdx │ │ │ │ │ ├── layout.tsx │ │ │ │ │ └── menu.md │ │ │ │ ├── examples/ │ │ │ │ │ ├── [...id]/ │ │ │ │ │ │ ├── examples.css │ │ │ │ │ │ └── index!.tsx │ │ │ │ │ └── apps/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── examples-data.ts │ │ │ │ │ ├── examples-menu.json │ │ │ │ │ ├── introduction/ │ │ │ │ │ │ ├── hello-world/ │ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ │ ├── entry.server.tsx │ │ │ │ │ │ │ └── root.tsx │ │ │ │ │ │ └── runtime-less/ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ ├── entry.server.tsx │ │ │ │ │ │ └── root.tsx │ │ │ │ │ ├── partial/ │ │ │ │ │ │ └── hackernews-index/ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ ├── entry.server.tsx │ │ │ │ │ │ ├── hacker-news.css │ │ │ │ │ │ └── root.tsx │ │ │ │ │ ├── reactivity/ │ │ │ │ │ │ ├── auto-complete/ │ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ │ ├── entry.server.tsx │ │ │ │ │ │ │ └── root.tsx │ │ │ │ │ │ ├── counter/ │ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ │ ├── entry.server.tsx │ │ │ │ │ │ │ └── root.tsx │ │ │ │ │ │ └── task/ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ ├── entry.server.tsx │ │ │ │ │ │ └── root.tsx │ │ │ │ │ └── visibility/ │ │ │ │ │ └── clock/ │ │ │ │ │ ├── app.tsx │ │ │ │ │ ├── clock.css │ │ │ │ │ ├── entry.server.tsx │ │ │ │ │ └── root.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── playground/ │ │ │ │ │ ├── app/ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ ├── entry.server.tsx │ │ │ │ │ │ └── root.tsx │ │ │ │ │ ├── index!.tsx │ │ │ │ │ ├── playground-data.ts │ │ │ │ │ └── playground.css │ │ │ │ ├── plugin@builder.io-redirect.ts │ │ │ │ ├── plugin@redirects.ts │ │ │ │ ├── press/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── query/ │ │ │ │ │ ├── [id]/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── index.tsx │ │ │ │ ├── repl/ │ │ │ │ │ ├── [catchAll]/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── repl-sw.js/ │ │ │ │ │ └── entry.ts │ │ │ │ └── tutorial/ │ │ │ │ ├── component/ │ │ │ │ │ ├── basic/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── binding/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── composition/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── lite/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── composing/ │ │ │ │ │ ├── dollar/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── use/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── context/ │ │ │ │ │ └── basic/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── events/ │ │ │ │ │ ├── basic/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── document/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── preventdefault/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── programmatic/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── synchronous-sync/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── synchronous-visible/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── hooks/ │ │ │ │ │ ├── use-on/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── use-task/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── use-visible-task/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ ├── app.tsx │ │ │ │ │ │ └── clock.css │ │ │ │ │ └── solution/ │ │ │ │ │ ├── app.tsx │ │ │ │ │ └── clock.css │ │ │ │ ├── introduction/ │ │ │ │ │ ├── component/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── listeners/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── resource/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── store/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── projection/ │ │ │ │ │ ├── basic/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── fallback/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── slots/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── props/ │ │ │ │ │ ├── basic/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── closures/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── qrl/ │ │ │ │ │ ├── closures/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── data/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── optimizer/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── reactivity/ │ │ │ │ │ ├── explicit/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── resource/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── template/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── store/ │ │ │ │ │ ├── basic/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── no-serialize/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── recursive/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ ├── serialization/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── use-signal/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── style/ │ │ │ │ │ ├── scoped/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── styles/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── tutorial-content-footer.tsx │ │ │ │ ├── tutorial-content-header.tsx │ │ │ │ ├── tutorial-data.ts │ │ │ │ ├── tutorial-menu.json │ │ │ │ ├── tutorial.css │ │ │ │ ├── understanding/ │ │ │ │ │ ├── capturing/ │ │ │ │ │ │ ├── index.mdx │ │ │ │ │ │ ├── problem/ │ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ │ └── solution/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── treeshaking/ │ │ │ │ │ ├── index.mdx │ │ │ │ │ ├── problem/ │ │ │ │ │ │ └── app.tsx │ │ │ │ │ └── solution/ │ │ │ │ │ └── app.tsx │ │ │ │ └── welcome/ │ │ │ │ └── overview/ │ │ │ │ ├── index.md │ │ │ │ ├── problem/ │ │ │ │ │ └── app.tsx │ │ │ │ └── solution/ │ │ │ │ └── app.tsx │ │ │ └── utils/ │ │ │ └── utils.ts │ │ ├── test-urls.js │ │ ├── tsconfig.json │ │ ├── vite.config-repl-sw.mts │ │ ├── vite.config.mts │ │ ├── vite.repl-apps.ts │ │ ├── vite.source-resolver.ts │ │ ├── wrangler.jsonc │ │ └── wrangler.toml │ ├── eslint-plugin-qwik/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── examples.ts │ │ ├── index.ts │ │ ├── package.json │ │ ├── qwik.unit.ts │ │ ├── src/ │ │ │ ├── jsxAtag.ts │ │ │ ├── jsxImg.ts │ │ │ ├── jsxKey.ts │ │ │ ├── jsxNoScriptUrl.ts │ │ │ ├── loaderLocation.ts │ │ │ ├── noAsyncPreventDefault.ts │ │ │ ├── noReactProps.ts │ │ │ ├── noUseVisibleTask.ts │ │ │ ├── preferClasslist.ts │ │ │ ├── unusedServer.ts │ │ │ ├── useMethodUsage.ts │ │ │ └── validLexicalScope.ts │ │ └── tests/ │ │ ├── loader-location/ │ │ │ ├── invalid-loader-missing-export/ │ │ │ │ └── src/ │ │ │ │ └── routes/ │ │ │ │ └── index.tsx │ │ │ ├── valid-loader/ │ │ │ │ └── src/ │ │ │ │ └── routes/ │ │ │ │ └── index.tsx │ │ │ └── valid-loader-export/ │ │ │ └── src/ │ │ │ └── routes/ │ │ │ └── index.tsx │ │ ├── no-async-prevent-default/ │ │ │ ├── invalid-prevent-default-arrow.tsx │ │ │ ├── invalid-prevent-default.tsx │ │ │ ├── valid-prevent-default-arrow.tsx │ │ │ └── valid-prevent-default.tsx │ │ ├── no-use-visible-task/ │ │ │ └── invalid-no-comment.tsx │ │ ├── tsconfig.json │ │ ├── use-method-usage/ │ │ │ ├── invalid-outside-arrow-fn-inline-value.ts │ │ │ ├── invalid-outside-arrow-fn-inline.ts │ │ │ ├── invalid-outside-arrow-fn-return-value.ts │ │ │ ├── invalid-outside-arrow-fn-return.ts │ │ │ ├── invalid-outside-arrow-fn.ts │ │ │ ├── invalid-outside-function.ts │ │ │ ├── valid-exported-use-methods.ts │ │ │ ├── valid-exported-use-methonds-can-call-other-use-methods.ts │ │ │ └── valid-inside-component.tsx │ │ └── valid-lexical-scope/ │ │ ├── invalid-capture-class.tsx │ │ ├── invalid-capture-enum.tsx │ │ ├── invalid-capture-function-event.tsx │ │ ├── invalid-capture-function.tsx │ │ ├── invalid-capture-mutable-assignment.tsx │ │ ├── invalid-capture-symbol.tsx │ │ ├── invalid-mutable.tsx │ │ ├── invalid-props-nonserializable-tuple.tsx │ │ ├── invalid-use-method-factory.tsx │ │ ├── invalid-use-method-inline.tsx │ │ ├── valid-capture-jsxoutput.tsx │ │ ├── valid-capture-signal.tsx │ │ ├── valid-component-prop-function.tsx │ │ ├── valid-component-props-click.tsx │ │ ├── valid-component-props-tuple.tsx │ │ ├── valid-component-props.tsx │ │ ├── valid-constant.tsx │ │ ├── valid-file-scope.tsx │ │ ├── valid-no-serialize.tsx │ │ ├── valid-null-value.tsx │ │ ├── valid-ssr-stream.tsx │ │ ├── valid-use-doc.tsx │ │ ├── valid-use-method-factory.tsx │ │ ├── valid-use-task-getter.tsx │ │ └── valid-use-task.tsx │ ├── insights/ │ │ ├── .gitignore │ │ ├── .node-version │ │ ├── .npmrc │ │ ├── .prettierignore │ │ ├── .vscode/ │ │ │ ├── extensions.json │ │ │ ├── launch.json │ │ │ ├── qwik-city.code-snippets │ │ │ └── qwik.code-snippets │ │ ├── README.md │ │ ├── adapters/ │ │ │ └── netlify-edge/ │ │ │ └── vite.config.ts │ │ ├── drizzle/ │ │ │ ├── 0000_blue_blindfold.sql │ │ │ ├── 0001_sweet_virginia_dare.sql │ │ │ ├── 0002_exotic_earthquake.sql │ │ │ ├── 0003_late_titanium_man.sql │ │ │ ├── 0004_secret_justice.sql │ │ │ ├── 0005_cute_marvel_boy.sql │ │ │ ├── 0006_last_dakota_north.sql │ │ │ ├── 0007_large_vengeance.sql │ │ │ ├── 0008_handy_baron_zemo.sql │ │ │ ├── 0009_flat_celestials.sql │ │ │ ├── 0010_typical_lockheed.sql │ │ │ ├── 0011_thin_captain_stacy.sql │ │ │ ├── 0012_omniscient_leader.sql │ │ │ ├── 0013_brave_venus.sql │ │ │ ├── 0014_needy_ben_grimm.sql │ │ │ ├── 0015_complete_wolf_cub.sql │ │ │ ├── 0016_demonic_legion.sql │ │ │ ├── 0017_pink_maestro.sql │ │ │ ├── 0018_heavy_toad.sql │ │ │ ├── 0019_known_satana.sql │ │ │ └── meta/ │ │ │ ├── 0000_snapshot.json │ │ │ ├── 0001_snapshot.json │ │ │ ├── 0002_snapshot.json │ │ │ ├── 0003_snapshot.json │ │ │ ├── 0004_snapshot.json │ │ │ ├── 0005_snapshot.json │ │ │ ├── 0006_snapshot.json │ │ │ ├── 0007_snapshot.json │ │ │ ├── 0008_snapshot.json │ │ │ ├── 0009_snapshot.json │ │ │ ├── 0010_snapshot.json │ │ │ ├── 0011_snapshot.json │ │ │ ├── 0012_snapshot.json │ │ │ ├── 0013_snapshot.json │ │ │ ├── 0014_snapshot.json │ │ │ ├── 0015_snapshot.json │ │ │ ├── 0016_snapshot.json │ │ │ ├── 0017_snapshot.json │ │ │ ├── 0018_snapshot.json │ │ │ ├── 0019_snapshot.json │ │ │ └── _journal.json │ │ ├── drizzle.config.ts │ │ ├── eslint.config.mjs │ │ ├── package.json │ │ ├── public/ │ │ │ ├── _headers │ │ │ ├── manifest.json │ │ │ └── robots.txt │ │ ├── scripts/ │ │ │ └── db.migrate.cjs │ │ ├── src/ │ │ │ ├── components/ │ │ │ │ ├── app-card/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── avatar/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── bundle/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── button/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── container/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── gauge/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── header/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── histogram/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── icons/ │ │ │ │ │ ├── apps.tsx │ │ │ │ │ ├── bundle.tsx │ │ │ │ │ ├── close.tsx │ │ │ │ │ ├── copy.tsx │ │ │ │ │ ├── dark-mode.tsx │ │ │ │ │ ├── dashboard.tsx │ │ │ │ │ ├── disk.tsx │ │ │ │ │ ├── edge.tsx │ │ │ │ │ ├── edit.tsx │ │ │ │ │ ├── error.tsx │ │ │ │ │ ├── github.tsx │ │ │ │ │ ├── light-mode.tsx │ │ │ │ │ ├── manifest.tsx │ │ │ │ │ ├── qwik.tsx │ │ │ │ │ ├── routes.tsx │ │ │ │ │ ├── slow.tsx │ │ │ │ │ └── symbol.tsx │ │ │ │ ├── layout/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── minifest-tile/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── popup-manager/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── router-head/ │ │ │ │ │ └── router-head.tsx │ │ │ │ └── symbol-tile/ │ │ │ │ └── index.tsx │ │ │ ├── db/ │ │ │ │ ├── README.md │ │ │ │ ├── index.ts │ │ │ │ ├── logging.ts │ │ │ │ ├── query-helpers.ts │ │ │ │ ├── query.ts │ │ │ │ ├── schema.ts │ │ │ │ ├── sql-edges.ts │ │ │ │ ├── sql-manifest.ts │ │ │ │ ├── sql-routes.ts │ │ │ │ └── sql-user.ts │ │ │ ├── entry.dev.tsx │ │ │ ├── entry.netlify-edge.tsx │ │ │ ├── entry.preview.tsx │ │ │ ├── entry.ssr.tsx │ │ │ ├── global.css │ │ │ ├── root.tsx │ │ │ ├── routes/ │ │ │ │ ├── api/ │ │ │ │ │ └── v1/ │ │ │ │ │ └── [publicApiKey]/ │ │ │ │ │ ├── bundles/ │ │ │ │ │ │ ├── bundles.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── strategy/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── layout.ts │ │ │ │ │ └── post/ │ │ │ │ │ ├── error/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── manifest/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── app/ │ │ │ │ │ ├── [publicApiKey]/ │ │ │ │ │ │ ├── app.form.tsx │ │ │ │ │ │ ├── edit/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── errors/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── layout.tsx │ │ │ │ │ │ ├── manifests/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── routes/ │ │ │ │ │ │ │ ├── [route]/ │ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── symbols/ │ │ │ │ │ │ ├── bundles/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── edge/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ ├── outgoing/ │ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ │ └── slow/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── add/ │ │ │ │ │ │ ├── index.tsx │ │ │ │ │ │ └── styles.module.css │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── layout.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── plugin@auth.ts │ │ │ │ ├── plugin@db.ts │ │ │ │ ├── service-worker.ts │ │ │ │ └── test/ │ │ │ │ ├── counter/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── visible-task/ │ │ │ │ └── index.tsx │ │ │ ├── routes.config.tsx │ │ │ ├── routes.gen.d.ts │ │ │ ├── stats/ │ │ │ │ ├── clustering.unit.ts │ │ │ │ ├── edges.ts │ │ │ │ ├── edges.unit.ts │ │ │ │ ├── vector.ts │ │ │ │ └── vector.unit.ts │ │ │ └── types/ │ │ │ └── q-manifest.ts │ │ ├── tsconfig.json │ │ ├── vite.config.ts │ │ └── vitest.config.ts │ ├── qwik/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── build.d.ts │ │ ├── global.d.ts │ │ ├── jsx-dev-runtime.d.ts │ │ ├── jsx-runtime.d.ts │ │ ├── loader.d.ts │ │ ├── optimizer.d.ts │ │ ├── package.json │ │ ├── qwik-cli.cjs │ │ ├── server.d.ts │ │ ├── src/ │ │ │ ├── api-extractor.json │ │ │ ├── build/ │ │ │ │ ├── api-extractor.json │ │ │ │ ├── index.dev.ts │ │ │ │ ├── index.prod.ts │ │ │ │ ├── index.ts │ │ │ │ └── qwik.build.api.md │ │ │ ├── cli/ │ │ │ │ ├── add/ │ │ │ │ │ ├── print-add-help.ts │ │ │ │ │ ├── run-add-command.ts │ │ │ │ │ ├── run-add-interactive.ts │ │ │ │ │ ├── update-app.ts │ │ │ │ │ ├── update-files.ts │ │ │ │ │ ├── update-files.unit.ts │ │ │ │ │ └── update-vite-config.ts │ │ │ │ ├── check-client/ │ │ │ │ │ └── index.ts │ │ │ │ ├── code-mod/ │ │ │ │ │ ├── code-mod.ts │ │ │ │ │ └── code-mod.unit.ts │ │ │ │ ├── index.ts │ │ │ │ ├── joke/ │ │ │ │ │ └── run-joke-command.ts │ │ │ │ ├── migrate-v2/ │ │ │ │ │ ├── rename-import.ts │ │ │ │ │ ├── replace-package.ts │ │ │ │ │ ├── run-migration.ts │ │ │ │ │ ├── tools/ │ │ │ │ │ │ ├── binary-extensions.ts │ │ │ │ │ │ └── visit-not-ignored-files.ts │ │ │ │ │ ├── update-configurations.ts │ │ │ │ │ ├── update-dependencies.ts │ │ │ │ │ └── versions.ts │ │ │ │ ├── new/ │ │ │ │ │ ├── print-new-help.ts │ │ │ │ │ ├── run-new-command.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── qwik.cjs │ │ │ │ ├── run.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils/ │ │ │ │ ├── app-command.ts │ │ │ │ ├── install-deps.ts │ │ │ │ ├── integrations.ts │ │ │ │ ├── log.ts │ │ │ │ ├── run-build-command.ts │ │ │ │ ├── templates.ts │ │ │ │ └── utils.ts │ │ │ ├── core/ │ │ │ │ ├── api-extractor.json │ │ │ │ ├── component/ │ │ │ │ │ ├── component.public.ts │ │ │ │ │ └── component.unit.tsx │ │ │ │ ├── components/ │ │ │ │ │ └── prefetch.ts │ │ │ │ ├── container/ │ │ │ │ │ ├── container.ts │ │ │ │ │ ├── index.html │ │ │ │ │ ├── pause.ts │ │ │ │ │ ├── pause.unit.tsx │ │ │ │ │ ├── render.unit.tsx │ │ │ │ │ ├── resume.ts │ │ │ │ │ ├── serializers.ts │ │ │ │ │ ├── serializers.unit.ts │ │ │ │ │ └── store.unit.tsx │ │ │ │ ├── document.ts │ │ │ │ ├── error/ │ │ │ │ │ ├── assert.ts │ │ │ │ │ └── error.ts │ │ │ │ ├── examples.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── internal.ts │ │ │ │ ├── platform/ │ │ │ │ │ ├── platform.ts │ │ │ │ │ ├── platform.unit.ts │ │ │ │ │ ├── readme.md │ │ │ │ │ └── types.ts │ │ │ │ ├── preloader/ │ │ │ │ │ ├── bundle-graph.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── preloader.unit.ts │ │ │ │ │ ├── queue.ts │ │ │ │ │ └── types.ts │ │ │ │ ├── qrl/ │ │ │ │ │ ├── inlined-fn.ts │ │ │ │ │ ├── qrl-class.ts │ │ │ │ │ ├── qrl.public.ts │ │ │ │ │ ├── qrl.ts │ │ │ │ │ └── qrl.unit.ts │ │ │ │ ├── qwik.core.api.md │ │ │ │ ├── readme.md │ │ │ │ ├── render/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── dom/ │ │ │ │ │ │ ├── notify-render.ts │ │ │ │ │ │ ├── operations.ts │ │ │ │ │ │ ├── render-dom.ts │ │ │ │ │ │ ├── render.public.ts │ │ │ │ │ │ ├── render.unit.tsx │ │ │ │ │ │ ├── signals.ts │ │ │ │ │ │ ├── virtual-element.ts │ │ │ │ │ │ └── visitor.ts │ │ │ │ │ ├── error-handling.ts │ │ │ │ │ ├── execute-component.ts │ │ │ │ │ ├── execute-component.unit.ts │ │ │ │ │ ├── fast-calls.ts │ │ │ │ │ ├── jsx/ │ │ │ │ │ │ ├── README.md │ │ │ │ │ │ ├── factory.ts │ │ │ │ │ │ ├── factory.unit.ts │ │ │ │ │ │ ├── jsx-runtime.ts │ │ │ │ │ │ ├── jsx-runtime.unit.ts │ │ │ │ │ │ ├── slot.public.ts │ │ │ │ │ │ ├── types/ │ │ │ │ │ │ │ ├── jsx-generated.ts │ │ │ │ │ │ │ ├── jsx-node.ts │ │ │ │ │ │ │ ├── jsx-qwik-attributes.ts │ │ │ │ │ │ │ ├── jsx-qwik-elements.ts │ │ │ │ │ │ │ ├── jsx-qwik-events.ts │ │ │ │ │ │ │ ├── jsx-qwik.ts │ │ │ │ │ │ │ └── jsx-types.unit.tsx │ │ │ │ │ │ └── utils.public.ts │ │ │ │ │ ├── ssr/ │ │ │ │ │ │ ├── render-ssr.ts │ │ │ │ │ │ └── render-ssr.unit.tsx │ │ │ │ │ ├── sync-qrl.unit.tsx │ │ │ │ │ └── types.ts │ │ │ │ ├── state/ │ │ │ │ │ ├── common.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── context.ts │ │ │ │ │ ├── listeners.ts │ │ │ │ │ ├── signal.ts │ │ │ │ │ └── store.ts │ │ │ │ ├── style/ │ │ │ │ │ ├── qrl-styles.ts │ │ │ │ │ ├── scoped-stylesheet.ts │ │ │ │ │ └── scoped-stylesheet.unit.ts │ │ │ │ ├── use/ │ │ │ │ │ ├── use-context.ts │ │ │ │ │ ├── use-core.ts │ │ │ │ │ ├── use-env-data.ts │ │ │ │ │ ├── use-error-boundary.ts │ │ │ │ │ ├── use-id.ts │ │ │ │ │ ├── use-lexical-scope.public.ts │ │ │ │ │ ├── use-locale.ts │ │ │ │ │ ├── use-on.ts │ │ │ │ │ ├── use-on.unit.ts │ │ │ │ │ ├── use-resource.ts │ │ │ │ │ ├── use-sequential-scope.ts │ │ │ │ │ ├── use-signal.ts │ │ │ │ │ ├── use-store.public.ts │ │ │ │ │ ├── use-styles.ts │ │ │ │ │ ├── use-task.ts │ │ │ │ │ └── use-task.unit.ts │ │ │ │ ├── util/ │ │ │ │ │ ├── README.md │ │ │ │ │ ├── case.ts │ │ │ │ │ ├── case.unit.ts │ │ │ │ │ ├── dom.ts │ │ │ │ │ ├── element.ts │ │ │ │ │ ├── event.ts │ │ │ │ │ ├── flyweight.ts │ │ │ │ │ ├── hash_code.ts │ │ │ │ │ ├── implicit_dollar.ts │ │ │ │ │ ├── log.ts │ │ │ │ │ ├── markers.ts │ │ │ │ │ ├── promises.ts │ │ │ │ │ ├── qdev.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── unitless_number.ts │ │ │ │ └── version.ts │ │ │ ├── jsx-runtime.ts │ │ │ ├── napi/ │ │ │ │ ├── Cargo.toml │ │ │ │ ├── Cargo.toml.template │ │ │ │ ├── build.rs │ │ │ │ ├── napi.config.json │ │ │ │ ├── src/ │ │ │ │ │ └── lib.rs │ │ │ │ └── test.cjs │ │ │ ├── optimizer/ │ │ │ │ ├── api-extractor.json │ │ │ │ ├── cli/ │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ └── src/ │ │ │ │ │ └── main.rs │ │ │ │ ├── core/ │ │ │ │ │ ├── Cargo.toml │ │ │ │ │ ├── Makefile │ │ │ │ │ ├── README.md │ │ │ │ │ ├── benches/ │ │ │ │ │ │ └── transform.rs │ │ │ │ │ └── src/ │ │ │ │ │ ├── add_side_effect.rs │ │ │ │ │ ├── clean_side_effects.rs │ │ │ │ │ ├── code_move.rs │ │ │ │ │ ├── collector.rs │ │ │ │ │ ├── const_replace.rs │ │ │ │ │ ├── entry_strategy.rs │ │ │ │ │ ├── errors.rs │ │ │ │ │ ├── filter_exports.rs │ │ │ │ │ ├── fixtures/ │ │ │ │ │ │ └── index.qwik.mjs │ │ │ │ │ ├── has_branches.rs │ │ │ │ │ ├── inlined_fn.rs │ │ │ │ │ ├── is_immutable.rs │ │ │ │ │ ├── lib.rs │ │ │ │ │ ├── package_json.rs │ │ │ │ │ ├── parse.rs │ │ │ │ │ ├── props_destructuring.rs │ │ │ │ │ ├── snapshots/ │ │ │ │ │ │ ├── qwik_core__test__example_1.snap │ │ │ │ │ │ ├── qwik_core__test__example_10.snap │ │ │ │ │ │ ├── qwik_core__test__example_11.snap │ │ │ │ │ │ ├── qwik_core__test__example_2.snap │ │ │ │ │ │ ├── qwik_core__test__example_3.snap │ │ │ │ │ │ ├── qwik_core__test__example_4.snap │ │ │ │ │ │ ├── qwik_core__test__example_5.snap │ │ │ │ │ │ ├── qwik_core__test__example_6.snap │ │ │ │ │ │ ├── qwik_core__test__example_7.snap │ │ │ │ │ │ ├── qwik_core__test__example_8.snap │ │ │ │ │ │ ├── qwik_core__test__example_9.snap │ │ │ │ │ │ ├── qwik_core__test__example_build_server.snap │ │ │ │ │ │ ├── qwik_core__test__example_capture_imports.snap │ │ │ │ │ │ ├── qwik_core__test__example_capturing_fn_class.snap │ │ │ │ │ │ ├── qwik_core__test__example_class_name.snap │ │ │ │ │ │ ├── qwik_core__test__example_custom_inlined_functions.snap │ │ │ │ │ │ ├── qwik_core__test__example_dead_code.snap │ │ │ │ │ │ ├── qwik_core__test__example_default_export.snap │ │ │ │ │ │ ├── qwik_core__test__example_default_export_index.snap │ │ │ │ │ │ ├── qwik_core__test__example_default_export_invalid_ident.snap │ │ │ │ │ │ ├── qwik_core__test__example_derived_signals_children.snap │ │ │ │ │ │ ├── qwik_core__test__example_derived_signals_cmp.snap │ │ │ │ │ │ ├── qwik_core__test__example_derived_signals_complext_children.snap │ │ │ │ │ │ ├── qwik_core__test__example_derived_signals_div.snap │ │ │ │ │ │ ├── qwik_core__test__example_derived_signals_multiple_children.snap │ │ │ │ │ │ ├── qwik_core__test__example_dev_mode.snap │ │ │ │ │ │ ├── qwik_core__test__example_dev_mode_inlined.snap │ │ │ │ │ │ ├── qwik_core__test__example_drop_side_effects.snap │ │ │ │ │ │ ├── qwik_core__test__example_explicit_ext_no_transpile.snap │ │ │ │ │ │ ├── qwik_core__test__example_explicit_ext_transpile.snap │ │ │ │ │ │ ├── qwik_core__test__example_export_issue.snap │ │ │ │ │ │ ├── qwik_core__test__example_exports.snap │ │ │ │ │ │ ├── qwik_core__test__example_fix_dynamic_import.snap │ │ │ │ │ │ ├── qwik_core__test__example_functional_component.snap │ │ │ │ │ │ ├── qwik_core__test__example_functional_component_2.snap │ │ │ │ │ │ ├── qwik_core__test__example_functional_component_capture_props.snap │ │ │ │ │ │ ├── qwik_core__test__example_getter_generation.snap │ │ │ │ │ │ ├── qwik_core__test__example_immutable_analysis.snap │ │ │ │ │ │ ├── qwik_core__test__example_immutable_function_components.snap │ │ │ │ │ │ ├── qwik_core__test__example_import_assertion.snap │ │ │ │ │ │ ├── qwik_core__test__example_inlined_entry_strategy.snap │ │ │ │ │ │ ├── qwik_core__test__example_input_bind.snap │ │ │ │ │ │ ├── qwik_core__test__example_invalid_references.snap │ │ │ │ │ │ ├── qwik_core__test__example_invalid_segment_expr1.snap │ │ │ │ │ │ ├── qwik_core__test__example_issue_33443.snap │ │ │ │ │ │ ├── qwik_core__test__example_issue_4438.snap │ │ │ │ │ │ ├── qwik_core__test__example_jsx.snap │ │ │ │ │ │ ├── qwik_core__test__example_jsx_import_source.snap │ │ │ │ │ │ ├── qwik_core__test__example_jsx_keyed.snap │ │ │ │ │ │ ├── qwik_core__test__example_jsx_keyed_dev.snap │ │ │ │ │ │ ├── qwik_core__test__example_jsx_listeners.snap │ │ │ │ │ │ ├── qwik_core__test__example_lightweight_functional.snap │ │ │ │ │ │ ├── qwik_core__test__example_manual_chunks.snap │ │ │ │ │ │ ├── qwik_core__test__example_missing_custom_inlined_functions.snap │ │ │ │ │ │ ├── qwik_core__test__example_multi_capture.snap │ │ │ │ │ │ ├── qwik_core__test__example_mutable_children.snap │ │ │ │ │ │ ├── qwik_core__test__example_noop_dev_mode.snap │ │ │ │ │ │ ├── qwik_core__test__example_of_synchronous_qrl.snap │ │ │ │ │ │ ├── qwik_core__test__example_optimization_issue_3542.snap │ │ │ │ │ │ ├── qwik_core__test__example_optimization_issue_3561.snap │ │ │ │ │ │ ├── qwik_core__test__example_optimization_issue_3795.snap │ │ │ │ │ │ ├── qwik_core__test__example_optimization_issue_4386.snap │ │ │ │ │ │ ├── qwik_core__test__example_parsed_inlined_qrls.snap │ │ │ │ │ │ ├── qwik_core__test__example_preserve_filenames.snap │ │ │ │ │ │ ├── qwik_core__test__example_preserve_filenames_segments.snap │ │ │ │ │ │ ├── qwik_core__test__example_prod_node.snap │ │ │ │ │ │ ├── qwik_core__test__example_props_optimization.snap │ │ │ │ │ │ ├── qwik_core__test__example_qwik_conflict.snap │ │ │ │ │ │ ├── qwik_core__test__example_qwik_react.snap │ │ │ │ │ │ ├── qwik_core__test__example_qwik_react_inline.snap │ │ │ │ │ │ ├── qwik_core__test__example_qwik_sdk_inline.snap │ │ │ │ │ │ ├── qwik_core__test__example_reg_ctx_name_segments.snap │ │ │ │ │ │ ├── qwik_core__test__example_reg_ctx_name_segments_hoisted.snap │ │ │ │ │ │ ├── qwik_core__test__example_reg_ctx_name_segments_inlined.snap │ │ │ │ │ │ ├── qwik_core__test__example_renamed_exports.snap │ │ │ │ │ │ ├── qwik_core__test__example_server_auth.snap │ │ │ │ │ │ ├── qwik_core__test__example_skip_transform.snap │ │ │ │ │ │ ├── qwik_core__test__example_spread_jsx.snap │ │ │ │ │ │ ├── qwik_core__test__example_strip_client_code.snap │ │ │ │ │ │ ├── qwik_core__test__example_strip_exports_unused.snap │ │ │ │ │ │ ├── qwik_core__test__example_strip_exports_used.snap │ │ │ │ │ │ ├── qwik_core__test__example_strip_server_code.snap │ │ │ │ │ │ ├── qwik_core__test__example_transpile_jsx_only.snap │ │ │ │ │ │ ├── qwik_core__test__example_transpile_ts_only.snap │ │ │ │ │ │ ├── qwik_core__test__example_ts_enums.snap │ │ │ │ │ │ ├── qwik_core__test__example_ts_enums_issue_1341.snap │ │ │ │ │ │ ├── qwik_core__test__example_ts_enums_no_transpile.snap │ │ │ │ │ │ ├── qwik_core__test__example_use_client_effect.snap │ │ │ │ │ │ ├── qwik_core__test__example_use_optimization.snap │ │ │ │ │ │ ├── qwik_core__test__example_use_server_mount.snap │ │ │ │ │ │ ├── qwik_core__test__example_with_style.snap │ │ │ │ │ │ ├── qwik_core__test__example_with_tagname.snap │ │ │ │ │ │ ├── qwik_core__test__impure_template_fns.snap │ │ │ │ │ │ ├── qwik_core__test__issue_117.snap │ │ │ │ │ │ ├── qwik_core__test__issue_150.snap │ │ │ │ │ │ ├── qwik_core__test__issue_476.snap │ │ │ │ │ │ ├── qwik_core__test__issue_5008.snap │ │ │ │ │ │ ├── qwik_core__test__issue_964.snap │ │ │ │ │ │ ├── qwik_core__test__lib_mode_fn_signal.snap │ │ │ │ │ │ ├── qwik_core__test__relative_paths.snap │ │ │ │ │ │ ├── qwik_core__test__special_jsx.snap │ │ │ │ │ │ └── qwik_core__test__support_windows_paths.snap │ │ │ │ │ ├── test.rs │ │ │ │ │ ├── transform.rs │ │ │ │ │ ├── utils.rs │ │ │ │ │ └── words.rs │ │ │ │ └── src/ │ │ │ │ ├── index.ts │ │ │ │ ├── manifest.ts │ │ │ │ ├── optimizer.ts │ │ │ │ ├── path.ts │ │ │ │ ├── platform.ts │ │ │ │ ├── plugins/ │ │ │ │ │ ├── bundle-graph.ts │ │ │ │ │ ├── bundle-graph.unit.ts │ │ │ │ │ ├── click-to-component.html │ │ │ │ │ ├── error-host.html │ │ │ │ │ ├── eslint-plugin.ts │ │ │ │ │ ├── fixture-output-bundles.json │ │ │ │ │ ├── image-size-runtime.html │ │ │ │ │ ├── image-size-server.ts │ │ │ │ │ ├── perf-warning.html │ │ │ │ │ ├── plugin.ts │ │ │ │ │ ├── plugin.unit.ts │ │ │ │ │ ├── rollup.ts │ │ │ │ │ ├── rollup.unit.ts │ │ │ │ │ ├── utils.ts │ │ │ │ │ ├── vite-dev-server.ts │ │ │ │ │ ├── vite-dev-server.unit.ts │ │ │ │ │ ├── vite-error.ts │ │ │ │ │ ├── vite-utils.ts │ │ │ │ │ ├── vite.ts │ │ │ │ │ └── vite.unit.ts │ │ │ │ ├── qwik-binding-map.ts │ │ │ │ ├── qwik.optimizer.api.md │ │ │ │ ├── scripts.ts │ │ │ │ ├── types.ts │ │ │ │ └── versions.ts │ │ │ ├── qwikloader.ts │ │ │ ├── qwikloader.unit.ts │ │ │ ├── server/ │ │ │ │ ├── api-extractor.json │ │ │ │ ├── index.ts │ │ │ │ ├── platform.ts │ │ │ │ ├── platform.unit.ts │ │ │ │ ├── preload-impl.ts │ │ │ │ ├── preload-strategy.ts │ │ │ │ ├── preload-utils.ts │ │ │ │ ├── preload-utils.unit.ts │ │ │ │ ├── preloading.md │ │ │ │ ├── qwik.server.api.md │ │ │ │ ├── render.ts │ │ │ │ ├── scripts.ts │ │ │ │ ├── server-modules.d.ts │ │ │ │ ├── types.ts │ │ │ │ └── utils.ts │ │ │ ├── testing/ │ │ │ │ ├── README.md │ │ │ │ ├── api-extractor.json │ │ │ │ ├── document.ts │ │ │ │ ├── document.unit.ts │ │ │ │ ├── element-fixture.ts │ │ │ │ ├── expect-dom.tsx │ │ │ │ ├── html.ts │ │ │ │ ├── index.ts │ │ │ │ ├── library.ts │ │ │ │ ├── platform.ts │ │ │ │ ├── qwik.testing.api.md │ │ │ │ ├── types.ts │ │ │ │ ├── util.ts │ │ │ │ └── util.unit.ts │ │ │ └── wasm/ │ │ │ ├── Cargo.toml │ │ │ └── src/ │ │ │ └── lib.rs │ │ ├── testing.d.ts │ │ ├── tsconfig.json │ │ └── tsdoc.json │ ├── qwik-auth/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── package.json │ │ ├── src/ │ │ │ └── index.ts │ │ └── vite.config.ts │ ├── qwik-city/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── adapters/ │ │ │ ├── azure-swa/ │ │ │ │ └── vite.d.ts │ │ │ ├── bun-server/ │ │ │ │ └── vite.d.ts │ │ │ ├── cloud-run/ │ │ │ │ └── vite.d.ts │ │ │ ├── cloudflare-pages/ │ │ │ │ └── vite.d.ts │ │ │ ├── deno-server/ │ │ │ │ └── vite.d.ts │ │ │ ├── netlify-edge/ │ │ │ │ └── vite.d.ts │ │ │ ├── node-server/ │ │ │ │ └── vite.d.ts │ │ │ ├── shared/ │ │ │ │ └── vite.d.ts │ │ │ ├── static/ │ │ │ │ └── vite.d.ts │ │ │ └── vercel-edge/ │ │ │ └── vite.d.ts │ │ ├── global.d.ts │ │ ├── index.d.ts │ │ ├── middleware/ │ │ │ ├── aws-lambda.d.ts │ │ │ ├── azure-swa.d.ts │ │ │ ├── bun.d.ts │ │ │ ├── cloudflare-pages.d.ts │ │ │ ├── deno.d.ts │ │ │ ├── firebase.d.ts │ │ │ ├── netlify-edge.d.ts │ │ │ ├── node.d.ts │ │ │ ├── request-handler.d.ts │ │ │ └── vercel-edge.d.ts │ │ ├── modules.d.ts │ │ ├── package.json │ │ ├── service-worker.d.ts │ │ ├── src/ │ │ │ ├── adapters/ │ │ │ │ ├── azure-swa/ │ │ │ │ │ ├── adapter.azure-swa.api.md │ │ │ │ │ └── vite/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ └── index.ts │ │ │ │ ├── bun-server/ │ │ │ │ │ ├── adapter.bun-server.api.md │ │ │ │ │ └── vite/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ └── index.ts │ │ │ │ ├── cloud-run/ │ │ │ │ │ ├── adapter.cloud-run.api.md │ │ │ │ │ └── vite/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ └── index.ts │ │ │ │ ├── cloudflare-pages/ │ │ │ │ │ ├── adapter.cloudflare-pages.api.md │ │ │ │ │ └── vite/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ └── index.ts │ │ │ │ ├── deno-server/ │ │ │ │ │ ├── adapter.deno-server.api.md │ │ │ │ │ └── vite/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ └── index.ts │ │ │ │ ├── netlify-edge/ │ │ │ │ │ ├── adapter.netlify-edge.api.md │ │ │ │ │ └── vite/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ └── index.ts │ │ │ │ ├── node-server/ │ │ │ │ │ ├── adapter.node-server.api.md │ │ │ │ │ └── vite/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ └── index.ts │ │ │ │ ├── shared/ │ │ │ │ │ ├── adapter.shared.api.md │ │ │ │ │ └── vite/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── post-build.ts │ │ │ │ ├── static/ │ │ │ │ │ ├── adapter.static.api.md │ │ │ │ │ └── vite/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ └── index.ts │ │ │ │ └── vercel-edge/ │ │ │ │ ├── adapter.vercel-edge.api.md │ │ │ │ └── vite/ │ │ │ │ ├── api-extractor.json │ │ │ │ └── index.ts │ │ │ ├── api-extractor.json │ │ │ ├── buildtime/ │ │ │ │ ├── build-endpoints.unit.ts │ │ │ │ ├── build-layout.unit.ts │ │ │ │ ├── build-menus.unit.ts │ │ │ │ ├── build-pages-rewrited.unit.ts │ │ │ │ ├── build-pages.unit.ts │ │ │ │ ├── build.ts │ │ │ │ ├── context.ts │ │ │ │ ├── markdown/ │ │ │ │ │ ├── frontmatter.ts │ │ │ │ │ ├── frontmatter.unit.ts │ │ │ │ │ ├── markdown-url.ts │ │ │ │ │ ├── markdown-url.unit.ts │ │ │ │ │ ├── mdx.ts │ │ │ │ │ ├── mdx.unit.ts │ │ │ │ │ ├── menu.ts │ │ │ │ │ ├── menu.unit.ts │ │ │ │ │ ├── rehype.ts │ │ │ │ │ └── syntax-highlight.ts │ │ │ │ ├── routing/ │ │ │ │ │ ├── parse-pathname.ts │ │ │ │ │ ├── parse-pathname.unit.ts │ │ │ │ │ ├── resolve-source-file.ts │ │ │ │ │ ├── resolve-source-file.unit.ts │ │ │ │ │ ├── sort-routes.ts │ │ │ │ │ ├── sort-routes.unit.ts │ │ │ │ │ ├── source-file.ts │ │ │ │ │ ├── source-file.unit.ts │ │ │ │ │ ├── walk-routes-dir.ts │ │ │ │ │ └── walk-server-plugins.ts │ │ │ │ ├── runtime-generation/ │ │ │ │ │ ├── generate-entries.ts │ │ │ │ │ ├── generate-menus.ts │ │ │ │ │ ├── generate-qwik-city-plan.ts │ │ │ │ │ ├── generate-routes.ts │ │ │ │ │ ├── generate-server-plugins.ts │ │ │ │ │ ├── generate-service-worker.ts │ │ │ │ │ ├── sw-register-build.ts │ │ │ │ │ └── utils.ts │ │ │ │ ├── types.ts │ │ │ │ └── vite/ │ │ │ │ ├── api-extractor.json │ │ │ │ ├── config.ts │ │ │ │ ├── dev-server.ts │ │ │ │ ├── format-error.ts │ │ │ │ ├── get-route-imports.ts │ │ │ │ ├── get-route-imports.unit.ts │ │ │ │ ├── image-jsx.ts │ │ │ │ ├── image-jsx.unit.ts │ │ │ │ ├── index.ts │ │ │ │ ├── plugin.ts │ │ │ │ ├── qwik-city.buildtime.api.md │ │ │ │ ├── types.ts │ │ │ │ └── validate-plugin.ts │ │ │ ├── middleware/ │ │ │ │ ├── aws-lambda/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── middleware.aws-lambda.api.md │ │ │ │ ├── azure-swa/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── middleware.azure-swa.api.md │ │ │ │ ├── bun/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── middleware.bun.api.md │ │ │ │ ├── cloudflare-pages/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── middleware.cloudflare-pages.api.md │ │ │ │ ├── deno/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── middleware.deno.api.md │ │ │ │ ├── firebase/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── middleware.firebase.api.md │ │ │ │ ├── netlify-edge/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ ├── index.ts │ │ │ │ │ └── middleware.netlify-edge.api.md │ │ │ │ ├── node/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ ├── http.ts │ │ │ │ │ ├── http.unit.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── middleware.node.api.md │ │ │ │ │ └── node-fetch.ts │ │ │ │ ├── request-handler/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ ├── cache-control.ts │ │ │ │ │ ├── cookie.ts │ │ │ │ │ ├── cookie.unit.ts │ │ │ │ │ ├── error-handler.ts │ │ │ │ │ ├── form-parsing.unit.ts │ │ │ │ │ ├── generated/ │ │ │ │ │ │ ├── not-found-paths.ts │ │ │ │ │ │ └── static-paths.ts │ │ │ │ │ ├── http-status-codes.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── middleware.request-handler.api.md │ │ │ │ │ ├── mime-types.ts │ │ │ │ │ ├── polyfill.ts │ │ │ │ │ ├── polyfill.unit.ts │ │ │ │ │ ├── redirect-handler.ts │ │ │ │ │ ├── request-event.ts │ │ │ │ │ ├── request-event.unit.ts │ │ │ │ │ ├── request-handler.ts │ │ │ │ │ ├── resolve-request-handlers.ts │ │ │ │ │ ├── resolve-request-handlers.unit.ts │ │ │ │ │ ├── response-page.ts │ │ │ │ │ ├── rewrite-handler.ts │ │ │ │ │ ├── server-error.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ └── user-response.ts │ │ │ │ └── vercel-edge/ │ │ │ │ ├── api-extractor.json │ │ │ │ ├── index.ts │ │ │ │ └── middleware.vercel-edge.api.md │ │ │ ├── runtime/ │ │ │ │ ├── src/ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ ├── client-navigate.ts │ │ │ │ │ ├── client-navigate.unit.ts │ │ │ │ │ ├── constants.ts │ │ │ │ │ ├── contexts.ts │ │ │ │ │ ├── error-boundary.tsx │ │ │ │ │ ├── form-component.tsx │ │ │ │ │ ├── head.ts │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── link-component.tsx │ │ │ │ │ ├── qwik-city-component.tsx │ │ │ │ │ ├── qwik-city-plan.ts │ │ │ │ │ ├── qwik-city.runtime.api.md │ │ │ │ │ ├── route-matcher.ts │ │ │ │ │ ├── route-matcher.unit.ts │ │ │ │ │ ├── router-outlet-component.tsx │ │ │ │ │ ├── routing.ts │ │ │ │ │ ├── routing.unit.ts │ │ │ │ │ ├── scroll-restoration.ts │ │ │ │ │ ├── server-functions.ts │ │ │ │ │ ├── server-functions.unit.ts │ │ │ │ │ ├── service-worker/ │ │ │ │ │ │ ├── api-extractor.json │ │ │ │ │ │ ├── index.ts │ │ │ │ │ │ └── qwik-city.service-worker.api.md │ │ │ │ │ ├── spa-init.ts │ │ │ │ │ ├── sw-component.tsx │ │ │ │ │ ├── sw-register-runtime.ts │ │ │ │ │ ├── sw-register.ts │ │ │ │ │ ├── types.ts │ │ │ │ │ ├── use-endpoint.ts │ │ │ │ │ ├── use-functions.ts │ │ │ │ │ ├── utils.ts │ │ │ │ │ └── utils.unit.ts │ │ │ │ └── vite.config.mts │ │ │ ├── static/ │ │ │ │ ├── api-extractor.json │ │ │ │ ├── extract-params.ts │ │ │ │ ├── extract-params.unit.ts │ │ │ │ ├── index.ts │ │ │ │ ├── main-thread.ts │ │ │ │ ├── node/ │ │ │ │ │ ├── index.ts │ │ │ │ │ ├── node-main.ts │ │ │ │ │ ├── node-system.ts │ │ │ │ │ └── node-worker.ts │ │ │ │ ├── not-found.ts │ │ │ │ ├── qwik-city.static.api.md │ │ │ │ ├── routes.ts │ │ │ │ ├── types.ts │ │ │ │ └── worker-thread.ts │ │ │ └── utils/ │ │ │ ├── format.ts │ │ │ ├── format.unit.ts │ │ │ ├── fs.ts │ │ │ ├── fs.unit.ts │ │ │ ├── pathname.ts │ │ │ ├── pathname.unit.ts │ │ │ └── test-suite.ts │ │ ├── static.d.ts │ │ ├── tsconfig.json │ │ └── vite.d.ts │ ├── qwik-dom/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ └── package.json │ ├── qwik-labs/ │ │ ├── .gitignore │ │ ├── .prettierignore │ │ ├── README.md │ │ ├── eslint.config.mjs │ │ ├── package.json │ │ ├── src/ │ │ │ ├── devtools/ │ │ │ │ ├── index.ts │ │ │ │ └── json.ts │ │ │ ├── entry.dev.tsx │ │ │ ├── entry.ssr.tsx │ │ │ ├── index.ts │ │ │ ├── insights/ │ │ │ │ └── index.tsx │ │ │ ├── qwik-types/ │ │ │ │ ├── index.ts │ │ │ │ └── public-api.ts │ │ │ └── root.tsx │ │ ├── src-vite/ │ │ │ ├── index.ts │ │ │ ├── insights/ │ │ │ │ └── index.ts │ │ │ └── qwik-types/ │ │ │ ├── generator.ts │ │ │ ├── index.ts │ │ │ ├── prettify.ts │ │ │ └── vite.ts │ │ ├── tsconfig-vite.json │ │ ├── tsconfig.json │ │ ├── vite.config-src-vite.mts │ │ └── vite.config.mts │ ├── qwik-react/ │ │ ├── .npmignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── api-extractor.json │ │ ├── package.json │ │ ├── src/ │ │ │ ├── api-extractor.json │ │ │ ├── entry.dev.tsx │ │ │ ├── entry.ssr.tsx │ │ │ ├── examples/ │ │ │ │ └── app.tsx │ │ │ ├── index.qwik.ts │ │ │ ├── react/ │ │ │ │ ├── client.tsx │ │ │ │ ├── qwikify.tsx │ │ │ │ ├── server-render.tsx │ │ │ │ ├── slot.ts │ │ │ │ └── types.ts │ │ │ ├── root.tsx │ │ │ └── vite.ts │ │ ├── vite.config.mts │ │ └── vite.d.ts │ ├── qwik-worker/ │ │ ├── .npmignore │ │ ├── package.json │ │ ├── src/ │ │ │ ├── index.ts │ │ │ └── worker.js │ │ └── vite.config.ts │ └── supabase-auth-helpers-qwik/ │ ├── README.md │ ├── package.json │ ├── src/ │ │ ├── ambient.d.ts │ │ ├── index.ts │ │ └── utils/ │ │ ├── createBrowserClient.ts │ │ └── createServerClient.ts │ └── vite.config.ts ├── patches/ │ ├── density-clustering@1.3.0.patch │ └── domino@2.1.6.patch ├── pnpm-workspace.yaml ├── rust-toolchain ├── rustfmt.toml ├── scripts/ │ ├── api-docs.ts │ ├── api.ts │ ├── binding-platform.ts │ ├── binding-wasm.ts │ ├── build-clean.ts │ ├── build.ts │ ├── compiled-string-plugin.ts │ ├── create-qwik-cli.ts │ ├── docs_sync/ │ │ ├── fetch_hackmd.ts │ │ ├── index.ts │ │ ├── main.ts │ │ └── util.ts │ ├── e2e-cli.ts │ ├── eslint-docs.ts │ ├── eslint.ts │ ├── index.ts │ ├── link-local-package.ts │ ├── package-json.ts │ ├── qwik-auth.ts │ ├── qwik-city.ts │ ├── qwik-labs.ts │ ├── qwik-push-build-repos.ts │ ├── qwik-react.ts │ ├── qwik-worker.ts │ ├── release.ts │ ├── runBefore.ts │ ├── submodule-build.ts │ ├── submodule-cli.ts │ ├── submodule-core.ts │ ├── submodule-optimizer.ts │ ├── submodule-preloader.ts │ ├── submodule-qwikloader.ts │ ├── submodule-server.ts │ ├── submodule-testing.ts │ ├── supabase-auth-helpers.ts │ ├── tools/ │ │ └── preinstall-script.js │ ├── tsc-docs.ts │ ├── tsc.ts │ ├── types.d.ts │ ├── update-qwik-builds.ts │ ├── util.ts │ ├── validate-build.ts │ └── validate-cli.ts ├── starters/ │ ├── .gitignore │ ├── .prettierrc.json │ ├── README.md │ ├── adapters/ │ │ ├── aws-lambda/ │ │ │ ├── .eslintignore │ │ │ ├── .prettierignore │ │ │ ├── adapters/ │ │ │ │ └── aws-lambda/ │ │ │ │ └── vite.config.ts │ │ │ ├── gitignore │ │ │ ├── package.json │ │ │ ├── serverless.yml │ │ │ └── src/ │ │ │ └── entry_aws-lambda.tsx │ │ ├── azure-swa/ │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ └── azure-swa/ │ │ │ │ └── vite.config.ts │ │ │ ├── azure-functions/ │ │ │ │ └── host.json │ │ │ ├── gitignore │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ └── staticwebapp.config.json │ │ │ ├── src/ │ │ │ │ └── entry.azure-swa.tsx │ │ │ └── swa-cli.config.json │ │ ├── bun/ │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ └── bun/ │ │ │ │ └── vite.config.ts │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── entry.bun.ts │ │ ├── cloud-run/ │ │ │ ├── Dockerfile │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ └── cloud-run/ │ │ │ │ └── vite.config.ts │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── entry.cloud-run.tsx │ │ ├── cloudflare-pages/ │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ └── cloudflare-pages/ │ │ │ │ └── vite.config.ts │ │ │ ├── gitignore │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ ├── _headers │ │ │ │ └── _redirects │ │ │ └── src/ │ │ │ └── entry.cloudflare-pages.tsx │ │ ├── cloudflare-workers/ │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ └── cloudflare-workers/ │ │ │ │ └── vite.config.ts │ │ │ ├── gitignore │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ ├── .assetsignore │ │ │ │ ├── _headers │ │ │ │ └── _redirects │ │ │ ├── src/ │ │ │ │ └── entry.cloudflare-pages.tsx │ │ │ ├── worker-configuration.d.ts │ │ │ └── wrangler.jsonc │ │ ├── deno/ │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ └── deno/ │ │ │ │ └── vite.config.ts │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── entry.deno.ts │ │ ├── express/ │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ └── express/ │ │ │ │ └── vite.config.ts │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── entry.express.tsx │ │ ├── fastify/ │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ └── fastify/ │ │ │ │ └── vite.config.ts │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── entry.fastify.tsx │ │ │ └── plugins/ │ │ │ └── fastify-qwik.ts │ │ ├── firebase/ │ │ │ ├── .eslintignore │ │ │ ├── .prettierignore │ │ │ ├── adapters/ │ │ │ │ └── firebase/ │ │ │ │ └── vite.config.ts │ │ │ ├── firebase.json │ │ │ ├── functions/ │ │ │ │ ├── .gitkeep │ │ │ │ ├── index.js │ │ │ │ └── package.json │ │ │ ├── gitignore │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── entry-firebase.tsx │ │ ├── netlify-edge/ │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ └── netlify-edge/ │ │ │ │ └── vite.config.ts │ │ │ ├── gitignore │ │ │ ├── netlify.toml │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ └── _headers │ │ │ └── src/ │ │ │ └── entry.netlify-edge.tsx │ │ ├── node-server/ │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ └── node-server/ │ │ │ │ └── vite.config.ts │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── entry.node-server.tsx │ │ ├── static/ │ │ │ ├── README.md │ │ │ ├── adapters/ │ │ │ │ └── static/ │ │ │ │ └── vite.config.ts │ │ │ └── package.json │ │ └── vercel-edge/ │ │ ├── README.md │ │ ├── adapters/ │ │ │ └── vercel-edge/ │ │ │ └── vite.config.ts │ │ ├── gitignore │ │ ├── package.json │ │ ├── src/ │ │ │ └── entry.vercel-edge.tsx │ │ └── vercel.json │ ├── apps/ │ │ ├── base/ │ │ │ ├── .npmrc │ │ │ ├── .prettierignore │ │ │ ├── .vscode/ │ │ │ │ ├── extensions.json │ │ │ │ ├── launch.json │ │ │ │ ├── qwik-city.code-snippets │ │ │ │ ├── qwik.code-snippets │ │ │ │ └── settings.json │ │ │ ├── README.md │ │ │ ├── eslint.config.js │ │ │ ├── gitignore │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ ├── manifest.json │ │ │ │ └── robots.txt │ │ │ ├── qwik.env.d.ts │ │ │ ├── src/ │ │ │ │ ├── entry.dev.tsx │ │ │ │ ├── entry.preview.tsx │ │ │ │ ├── entry.ssr.tsx │ │ │ │ └── global.css │ │ │ ├── tsconfig.json │ │ │ └── vite.config.ts │ │ ├── e2e/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── components/ │ │ │ │ ├── async/ │ │ │ │ │ └── async.tsx │ │ │ │ ├── attributes/ │ │ │ │ │ └── attributes.tsx │ │ │ │ ├── broadcast-events/ │ │ │ │ │ └── broadcast-event.tsx │ │ │ │ ├── build-variables/ │ │ │ │ │ └── build.tsx │ │ │ │ ├── computed/ │ │ │ │ │ └── computed.tsx │ │ │ │ ├── containers/ │ │ │ │ │ └── container.tsx │ │ │ │ ├── context/ │ │ │ │ │ └── context.tsx │ │ │ │ ├── effect-client/ │ │ │ │ │ └── effect-client.tsx │ │ │ │ ├── events/ │ │ │ │ │ ├── events-client.tsx │ │ │ │ │ └── events.tsx │ │ │ │ ├── factory/ │ │ │ │ │ ├── factory.tsx │ │ │ │ │ └── utils.tsx │ │ │ │ ├── lexical-scope/ │ │ │ │ │ └── lexicalScope.tsx │ │ │ │ ├── mount/ │ │ │ │ │ └── mount.tsx │ │ │ │ ├── no-resume/ │ │ │ │ │ └── no-resume.tsx │ │ │ │ ├── ref/ │ │ │ │ │ └── ref.tsx │ │ │ │ ├── render/ │ │ │ │ │ └── render.tsx │ │ │ │ ├── resource/ │ │ │ │ │ ├── resource-fn.tsx │ │ │ │ │ ├── resource-serialization.tsx │ │ │ │ │ ├── resource.tsx │ │ │ │ │ └── weather.tsx │ │ │ │ ├── resuming/ │ │ │ │ │ ├── resuming.tsx │ │ │ │ │ └── sync-qrl.tsx │ │ │ │ ├── signals/ │ │ │ │ │ ├── Issue_5001.tsx │ │ │ │ │ ├── signals.tsx │ │ │ │ │ └── utils/ │ │ │ │ │ └── utils.tsx │ │ │ │ ├── slot/ │ │ │ │ │ ├── slot-remove.tsx │ │ │ │ │ └── slot.tsx │ │ │ │ ├── streaming/ │ │ │ │ │ ├── demo.tsx │ │ │ │ │ └── streaming.tsx │ │ │ │ ├── styles/ │ │ │ │ │ ├── child.css │ │ │ │ │ ├── child2.css │ │ │ │ │ ├── empty.css │ │ │ │ │ ├── parent.css │ │ │ │ │ ├── parent2.css │ │ │ │ │ └── styles.tsx │ │ │ │ ├── toggle/ │ │ │ │ │ └── toggle.tsx │ │ │ │ ├── treeshaking/ │ │ │ │ │ └── treeshaking.tsx │ │ │ │ ├── two-listeners/ │ │ │ │ │ └── twolisteners.tsx │ │ │ │ ├── useid/ │ │ │ │ │ └── useid.tsx │ │ │ │ └── watch/ │ │ │ │ └── watch.tsx │ │ │ ├── entry.ssr.tsx │ │ │ ├── global.css │ │ │ └── root.tsx │ │ ├── e2e-library/ │ │ │ └── package.json │ │ ├── empty/ │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ ├── manifest.json │ │ │ │ └── robots.txt │ │ │ └── src/ │ │ │ ├── components/ │ │ │ │ └── router-head/ │ │ │ │ └── router-head.tsx │ │ │ ├── global.css │ │ │ ├── root.tsx │ │ │ └── routes/ │ │ │ └── index.tsx │ │ ├── library/ │ │ │ ├── .prettierignore │ │ │ ├── README.md │ │ │ ├── eslint.config.js │ │ │ ├── gitignore │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── components/ │ │ │ │ │ ├── counter/ │ │ │ │ │ │ └── counter.tsx │ │ │ │ │ └── logo/ │ │ │ │ │ └── logo.tsx │ │ │ │ ├── entry.dev.tsx │ │ │ │ ├── entry.ssr.tsx │ │ │ │ ├── index.ts │ │ │ │ └── root.tsx │ │ │ ├── tsconfig.json │ │ │ └── vite.config.ts │ │ ├── perf.prod/ │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── components/ │ │ │ │ │ └── app/ │ │ │ │ │ └── app.tsx │ │ │ │ ├── entry.express.tsx │ │ │ │ ├── entry.ssr.tsx │ │ │ │ ├── global.css │ │ │ │ └── root.tsx │ │ │ └── vite.config.mts │ │ ├── playground/ │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ ├── manifest.json │ │ │ │ └── robots.txt │ │ │ └── src/ │ │ │ ├── components/ │ │ │ │ ├── router-head/ │ │ │ │ │ └── router-head.tsx │ │ │ │ └── starter/ │ │ │ │ ├── counter/ │ │ │ │ │ ├── counter.module.css │ │ │ │ │ └── counter.tsx │ │ │ │ ├── footer/ │ │ │ │ │ ├── footer.module.css │ │ │ │ │ └── footer.tsx │ │ │ │ ├── gauge/ │ │ │ │ │ ├── gauge.module.css │ │ │ │ │ └── index.tsx │ │ │ │ ├── header/ │ │ │ │ │ ├── header.module.css │ │ │ │ │ └── header.tsx │ │ │ │ ├── hero/ │ │ │ │ │ ├── hero.module.css │ │ │ │ │ └── hero.tsx │ │ │ │ ├── icons/ │ │ │ │ │ └── qwik.tsx │ │ │ │ ├── infobox/ │ │ │ │ │ ├── infobox.module.css │ │ │ │ │ └── infobox.tsx │ │ │ │ └── next-steps/ │ │ │ │ ├── next-steps.module.css │ │ │ │ └── next-steps.tsx │ │ │ ├── global.css │ │ │ ├── root.tsx │ │ │ └── routes/ │ │ │ ├── demo/ │ │ │ │ ├── flower/ │ │ │ │ │ ├── flower.css │ │ │ │ │ └── index.tsx │ │ │ │ └── todolist/ │ │ │ │ ├── index.tsx │ │ │ │ └── todolist.module.css │ │ │ ├── index.tsx │ │ │ ├── layout.tsx │ │ │ └── styles.css │ │ ├── preloader-test/ │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── src/ │ │ │ │ ├── components/ │ │ │ │ │ ├── generated/ │ │ │ │ │ │ ├── counter1.tsx │ │ │ │ │ │ ├── counter10.tsx │ │ │ │ │ │ ├── counter100.tsx │ │ │ │ │ │ ├── counter11.tsx │ │ │ │ │ │ ├── counter12.tsx │ │ │ │ │ │ ├── counter13.tsx │ │ │ │ │ │ ├── counter14.tsx │ │ │ │ │ │ ├── counter15.tsx │ │ │ │ │ │ ├── counter16.tsx │ │ │ │ │ │ ├── counter17.tsx │ │ │ │ │ │ ├── counter18.tsx │ │ │ │ │ │ ├── counter19.tsx │ │ │ │ │ │ ├── counter2.tsx │ │ │ │ │ │ ├── counter20.tsx │ │ │ │ │ │ ├── counter21.tsx │ │ │ │ │ │ ├── counter22.tsx │ │ │ │ │ │ ├── counter23.tsx │ │ │ │ │ │ ├── counter24.tsx │ │ │ │ │ │ ├── counter25.tsx │ │ │ │ │ │ ├── counter26.tsx │ │ │ │ │ │ ├── counter27.tsx │ │ │ │ │ │ ├── counter28.tsx │ │ │ │ │ │ ├── counter29.tsx │ │ │ │ │ │ ├── counter3.tsx │ │ │ │ │ │ ├── counter30.tsx │ │ │ │ │ │ ├── counter31.tsx │ │ │ │ │ │ ├── counter32.tsx │ │ │ │ │ │ ├── counter33.tsx │ │ │ │ │ │ ├── counter34.tsx │ │ │ │ │ │ ├── counter35.tsx │ │ │ │ │ │ ├── counter36.tsx │ │ │ │ │ │ ├── counter37.tsx │ │ │ │ │ │ ├── counter38.tsx │ │ │ │ │ │ ├── counter39.tsx │ │ │ │ │ │ ├── counter4.tsx │ │ │ │ │ │ ├── counter40.tsx │ │ │ │ │ │ ├── counter41.tsx │ │ │ │ │ │ ├── counter42.tsx │ │ │ │ │ │ ├── counter43.tsx │ │ │ │ │ │ ├── counter44.tsx │ │ │ │ │ │ ├── counter45.tsx │ │ │ │ │ │ ├── counter46.tsx │ │ │ │ │ │ ├── counter47.tsx │ │ │ │ │ │ ├── counter48.tsx │ │ │ │ │ │ ├── counter49.tsx │ │ │ │ │ │ ├── counter5.tsx │ │ │ │ │ │ ├── counter50.tsx │ │ │ │ │ │ ├── counter51.tsx │ │ │ │ │ │ ├── counter52.tsx │ │ │ │ │ │ ├── counter53.tsx │ │ │ │ │ │ ├── counter54.tsx │ │ │ │ │ │ ├── counter55.tsx │ │ │ │ │ │ ├── counter56.tsx │ │ │ │ │ │ ├── counter57.tsx │ │ │ │ │ │ ├── counter58.tsx │ │ │ │ │ │ ├── counter59.tsx │ │ │ │ │ │ ├── counter6.tsx │ │ │ │ │ │ ├── counter60.tsx │ │ │ │ │ │ ├── counter61.tsx │ │ │ │ │ │ ├── counter62.tsx │ │ │ │ │ │ ├── counter63.tsx │ │ │ │ │ │ ├── counter64.tsx │ │ │ │ │ │ ├── counter65.tsx │ │ │ │ │ │ ├── counter66.tsx │ │ │ │ │ │ ├── counter67.tsx │ │ │ │ │ │ ├── counter68.tsx │ │ │ │ │ │ ├── counter69.tsx │ │ │ │ │ │ ├── counter7.tsx │ │ │ │ │ │ ├── counter70.tsx │ │ │ │ │ │ ├── counter71.tsx │ │ │ │ │ │ ├── counter72.tsx │ │ │ │ │ │ ├── counter73.tsx │ │ │ │ │ │ ├── counter74.tsx │ │ │ │ │ │ ├── counter75.tsx │ │ │ │ │ │ ├── counter76.tsx │ │ │ │ │ │ ├── counter77.tsx │ │ │ │ │ │ ├── counter78.tsx │ │ │ │ │ │ ├── counter79.tsx │ │ │ │ │ │ ├── counter8.tsx │ │ │ │ │ │ ├── counter80.tsx │ │ │ │ │ │ ├── counter81.tsx │ │ │ │ │ │ ├── counter82.tsx │ │ │ │ │ │ ├── counter83.tsx │ │ │ │ │ │ ├── counter84.tsx │ │ │ │ │ │ ├── counter85.tsx │ │ │ │ │ │ ├── counter86.tsx │ │ │ │ │ │ ├── counter87.tsx │ │ │ │ │ │ ├── counter88.tsx │ │ │ │ │ │ ├── counter89.tsx │ │ │ │ │ │ ├── counter9.tsx │ │ │ │ │ │ ├── counter90.tsx │ │ │ │ │ │ ├── counter91.tsx │ │ │ │ │ │ ├── counter92.tsx │ │ │ │ │ │ ├── counter93.tsx │ │ │ │ │ │ ├── counter94.tsx │ │ │ │ │ │ ├── counter95.tsx │ │ │ │ │ │ ├── counter96.tsx │ │ │ │ │ │ ├── counter97.tsx │ │ │ │ │ │ ├── counter98.tsx │ │ │ │ │ │ ├── counter99.tsx │ │ │ │ │ │ ├── dynamic1.tsx │ │ │ │ │ │ ├── dynamic2.tsx │ │ │ │ │ │ ├── dynamic3.tsx │ │ │ │ │ │ ├── dynamic4.tsx │ │ │ │ │ │ ├── dynamic5.tsx │ │ │ │ │ │ ├── dynamic6.tsx │ │ │ │ │ │ ├── dynamic7.tsx │ │ │ │ │ │ ├── dynamic8.tsx │ │ │ │ │ │ ├── dynamic9.tsx │ │ │ │ │ │ └── show-dynamic.tsx │ │ │ │ │ └── router-head/ │ │ │ │ │ └── router-head.tsx │ │ │ │ ├── entry.dev.tsx │ │ │ │ ├── entry.preview.tsx │ │ │ │ ├── entry.ssr.tsx │ │ │ │ ├── global.css │ │ │ │ ├── root.tsx │ │ │ │ ├── routes/ │ │ │ │ │ ├── about/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── counters/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── form/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── hidden/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── layout.tsx │ │ │ │ └── vendor-lib/ │ │ │ │ ├── helper.ts │ │ │ │ ├── libA.ts │ │ │ │ └── libB.ts │ │ │ ├── tsconfig.json │ │ │ └── vite.config.ts │ │ ├── qwikcity-test/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── auth/ │ │ │ │ └── auth.ts │ │ │ ├── components/ │ │ │ │ ├── action/ │ │ │ │ │ └── action.tsx │ │ │ │ ├── breadcrumbs/ │ │ │ │ │ ├── breadcrumbs.css │ │ │ │ │ └── breadcrumbs.tsx │ │ │ │ ├── content-nav/ │ │ │ │ │ ├── content-nav.css │ │ │ │ │ └── content-nav.tsx │ │ │ │ ├── footer/ │ │ │ │ │ ├── footer.css │ │ │ │ │ └── footer.tsx │ │ │ │ ├── header/ │ │ │ │ │ ├── header.css │ │ │ │ │ └── header.tsx │ │ │ │ ├── menu/ │ │ │ │ │ ├── menu.css │ │ │ │ │ └── menu.tsx │ │ │ │ ├── provider/ │ │ │ │ │ └── provider.tsx │ │ │ │ └── router-head/ │ │ │ │ ├── router-head.tsx │ │ │ │ ├── social.tsx │ │ │ │ └── vendor.tsx │ │ │ ├── entry.ssr.tsx │ │ │ ├── global.css │ │ │ ├── root.tsx │ │ │ └── routes/ │ │ │ ├── (common)/ │ │ │ │ ├── (auth)/ │ │ │ │ │ ├── layout.css │ │ │ │ │ ├── layout.tsx │ │ │ │ │ ├── sign-in/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── sign-out/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── [...catchall]/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── [country]/ │ │ │ │ │ └── [city]/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── about-us/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── actions/ │ │ │ │ │ ├── actions.module.css │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── issue3183/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── issue3497/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── issue4444/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── issue5065/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── issue5463/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── login.tsx │ │ │ │ │ ├── multiple-handlers/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── validated/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── api/ │ │ │ │ │ ├── [org]/ │ │ │ │ │ │ └── [user].json/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── data.json/ │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── index@api.tsx │ │ │ │ │ ├── layout-api.css │ │ │ │ │ └── layout-api.tsx │ │ │ │ ├── blog/ │ │ │ │ │ ├── [...slug]/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── index.md │ │ │ │ │ └── layout.tsx │ │ │ │ ├── index.tsx │ │ │ │ ├── issue2644/ │ │ │ │ │ ├── data.ts │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── other/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── issue2878/ │ │ │ │ │ └── [...slug]/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── loaders/ │ │ │ │ │ ├── [id]/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── issue3979/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── loader-error/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── uncaught-server/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── location/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── mit/ │ │ │ │ │ └── index!.tsx │ │ │ │ ├── products/ │ │ │ │ │ ├── 404.tsx │ │ │ │ │ └── [id]/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── server-func/ │ │ │ │ │ ├── context/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── cookie/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── resource/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ ├── server-configs/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── server-error/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ ├── loader/ │ │ │ │ │ │ └── index.tsx │ │ │ │ │ └── primitive/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── streaming/ │ │ │ │ │ └── index.tsx │ │ │ │ └── treeshaking/ │ │ │ │ └── index.tsx │ │ │ ├── action-redirect-without-search-params/ │ │ │ │ └── index.tsx │ │ │ ├── action-redirect-without-search-params-target/ │ │ │ │ └── index.tsx │ │ │ ├── dashboard/ │ │ │ │ ├── dashboard.css │ │ │ │ ├── index.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── profile/ │ │ │ │ │ └── index.tsx │ │ │ │ └── settings/ │ │ │ │ └── index.tsx │ │ │ ├── docs/ │ │ │ │ ├── [category]/ │ │ │ │ │ └── [id]/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── getting-started/ │ │ │ │ │ └── index.md │ │ │ │ ├── index.tsx │ │ │ │ ├── layout.css │ │ │ │ ├── layout.tsx │ │ │ │ ├── menu.md │ │ │ │ └── overview/ │ │ │ │ └── index.md │ │ │ ├── error/ │ │ │ │ └── index.tsx │ │ │ ├── issue-loader/ │ │ │ │ ├── action.tsx │ │ │ │ └── index.tsx │ │ │ ├── issue-loader-serialization/ │ │ │ │ ├── action.tsx │ │ │ │ └── index.tsx │ │ │ ├── issue-route-with-search-params-and-action-redirect-without-search-params/ │ │ │ │ ├── action-redirect-without-search-params/ │ │ │ │ │ └── index.tsx │ │ │ │ └── action-redirect-without-search-params-target/ │ │ │ │ └── index.tsx │ │ │ ├── issue2441/ │ │ │ │ ├── abc.endpoint/ │ │ │ │ │ └── index.ts │ │ │ │ └── abc.page/ │ │ │ │ └── index.tsx │ │ │ ├── issue2829/ │ │ │ │ ├── a/ │ │ │ │ │ └── index.tsx │ │ │ │ └── b/ │ │ │ │ └── index.tsx │ │ │ ├── issue2890/ │ │ │ │ ├── a/ │ │ │ │ │ └── index.tsx │ │ │ │ └── b/ │ │ │ │ └── index.tsx │ │ │ ├── issue3438/ │ │ │ │ └── عربي/ │ │ │ │ └── index.mdx │ │ │ ├── issue4100/ │ │ │ │ └── index.tsx │ │ │ ├── issue4502/ │ │ │ │ ├── broken/ │ │ │ │ │ ├── index.tsx │ │ │ │ │ └── route/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── layout.tsx │ │ │ ├── issue4531/ │ │ │ │ ├── index.tsx │ │ │ │ └── layout.tsx │ │ │ ├── issue4679/ │ │ │ │ └── index.tsx │ │ │ ├── issue4792/ │ │ │ │ └── index.tsx │ │ │ ├── issue4956/ │ │ │ │ └── index.tsx │ │ │ ├── issue5665/ │ │ │ │ └── projects/ │ │ │ │ └── index.tsx │ │ │ ├── issue6660/ │ │ │ │ └── index.tsx │ │ │ ├── issue7182/ │ │ │ │ └── index.tsx │ │ │ ├── issue7254/ │ │ │ │ └── index.tsx │ │ │ ├── issue7732/ │ │ │ │ ├── a/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── b/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── c/ │ │ │ │ │ └── index.tsx │ │ │ │ └── layout.tsx │ │ │ ├── layout.tsx │ │ │ ├── locale/ │ │ │ │ └── index.tsx │ │ │ ├── mdx/ │ │ │ │ └── index.mdx │ │ │ ├── plugin@errors.tsx │ │ │ ├── plugin@header.ts │ │ │ ├── plugin@issue4722.tsx │ │ │ ├── plugin@redirect.ts │ │ │ ├── prevent-navigate/ │ │ │ │ ├── [id]/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── index.tsx │ │ │ │ └── layout.tsx │ │ │ ├── produkt/ │ │ │ │ └── index.tsx │ │ │ ├── scroll-restoration/ │ │ │ │ ├── hash/ │ │ │ │ │ └── index.tsx │ │ │ │ ├── layout.tsx │ │ │ │ ├── page-long/ │ │ │ │ │ └── index.tsx │ │ │ │ └── page-short/ │ │ │ │ └── index.tsx │ │ │ ├── search-params-redirect/ │ │ │ │ └── index.tsx │ │ │ └── some-code.js/ │ │ │ └── entry.ts │ │ ├── qwikcity-test.prod/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── components/ │ │ │ │ └── router-head/ │ │ │ │ ├── router-head.tsx │ │ │ │ ├── social.tsx │ │ │ │ └── vendor.tsx │ │ │ ├── entry.ssr.tsx │ │ │ ├── global.css │ │ │ ├── root.tsx │ │ │ └── routes/ │ │ │ ├── index.tsx │ │ │ └── server-function/ │ │ │ └── index.tsx │ │ ├── starter-partytown-test/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── components/ │ │ │ │ └── app/ │ │ │ │ └── app.tsx │ │ │ ├── entry.ssr.tsx │ │ │ ├── global.css │ │ │ └── root.tsx │ │ ├── todo-old-test/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── components/ │ │ │ │ ├── app/ │ │ │ │ │ ├── app.tsx │ │ │ │ │ ├── base.css │ │ │ │ │ └── index.css │ │ │ │ ├── body/ │ │ │ │ │ └── body.tsx │ │ │ │ ├── footer/ │ │ │ │ │ └── footer.tsx │ │ │ │ ├── header/ │ │ │ │ │ └── header.tsx │ │ │ │ └── item/ │ │ │ │ └── item.tsx │ │ │ ├── entry.dev.tsx │ │ │ ├── entry.ssr.tsx │ │ │ ├── root.tsx │ │ │ └── state/ │ │ │ └── state.ts │ │ └── todo-test/ │ │ ├── package.json │ │ └── src/ │ │ ├── components/ │ │ │ ├── app/ │ │ │ │ ├── app.tsx │ │ │ │ ├── base.css │ │ │ │ └── index.css │ │ │ ├── body/ │ │ │ │ └── body.tsx │ │ │ ├── footer/ │ │ │ │ └── footer.tsx │ │ │ ├── header/ │ │ │ │ └── header.tsx │ │ │ └── item/ │ │ │ └── item.tsx │ │ ├── entry.ssr.tsx │ │ ├── root.tsx │ │ └── state/ │ │ └── state.ts │ ├── dev-server.ts │ ├── e2e/ │ │ ├── e2e.attributes.spec.ts │ │ ├── e2e.build-variables.spec.ts │ │ ├── e2e.computed.spec.ts │ │ ├── e2e.containers.spec.ts │ │ ├── e2e.context.spec.ts │ │ ├── e2e.effect-client.spec.ts │ │ ├── e2e.events.spec.ts │ │ ├── e2e.factory.spec.ts │ │ ├── e2e.lexical-scope.spec.ts │ │ ├── e2e.mount.spec.ts │ │ ├── e2e.noresume.spec.ts │ │ ├── e2e.ref.spec.ts │ │ ├── e2e.render.spec.ts │ │ ├── e2e.resource.spec.ts │ │ ├── e2e.resuming.spec.ts │ │ ├── e2e.signals.spec.ts │ │ ├── e2e.slot.spec.ts │ │ ├── e2e.streaming.spec.ts │ │ ├── e2e.style.spec.ts │ │ ├── e2e.sync-qrl.spec.ts │ │ ├── e2e.toggle.spec.ts │ │ ├── e2e.two-listeners.spec.ts │ │ ├── e2e.use-id.spec.ts │ │ ├── e2e.watch.spec.ts │ │ ├── global.d.ts │ │ ├── qwikcity/ │ │ │ ├── actions.spec.ts │ │ │ ├── adapter.spec.ts │ │ │ ├── api.spec.ts │ │ │ ├── auth.spec.ts │ │ │ ├── catchall.spec.ts │ │ │ ├── error.spec.ts │ │ │ ├── fallback.spec.ts │ │ │ ├── loaders.spec.ts │ │ │ ├── locale.spec.ts │ │ │ ├── location.spec.ts │ │ │ ├── mdx.spec.ts │ │ │ ├── menu.spec.ts │ │ │ ├── nav.spec.ts │ │ │ ├── page.spec.ts │ │ │ ├── resource.spec.ts │ │ │ ├── server.spec.ts │ │ │ ├── url.spec.ts │ │ │ └── util.ts │ │ ├── starter-partytown.spec.ts │ │ ├── todo-old.spec.ts │ │ └── todo.spec.ts │ ├── features/ │ │ ├── auth/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── routes/ │ │ │ └── plugin@auth.ts │ │ ├── bootstrap/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── components/ │ │ │ │ └── bootstrap/ │ │ │ │ ├── alert.tsx │ │ │ │ ├── button.tsx │ │ │ │ ├── index.ts │ │ │ │ ├── navbar.tsx │ │ │ │ └── spinner.tsx │ │ │ ├── constants/ │ │ │ │ └── data.ts │ │ │ ├── models/ │ │ │ │ └── bootstrap.ts │ │ │ └── routes/ │ │ │ └── bootstrap/ │ │ │ ├── alerts/ │ │ │ │ └── index.tsx │ │ │ ├── buttons/ │ │ │ │ └── index.tsx │ │ │ ├── index.tsx │ │ │ ├── layout.tsx │ │ │ └── spinners/ │ │ │ └── index.tsx │ │ ├── builder.io/ │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── components/ │ │ │ │ ├── builder-registry.ts │ │ │ │ ├── counter/ │ │ │ │ │ ├── counter.module.css │ │ │ │ │ └── counter.tsx │ │ │ │ └── gauge/ │ │ │ │ ├── gauge.module.css │ │ │ │ └── index.tsx │ │ │ └── routes/ │ │ │ └── [...index]/ │ │ │ └── index.tsx │ │ ├── compiled-i18n/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── components/ │ │ │ │ └── locale-selector/ │ │ │ │ └── locale-selector.tsx │ │ │ ├── entry.ssr.tsx │ │ │ └── routes/ │ │ │ └── plugin@compiled-i18n.ts │ │ ├── cypress/ │ │ │ ├── cypress/ │ │ │ │ ├── fixtures/ │ │ │ │ │ └── example.json │ │ │ │ ├── support/ │ │ │ │ │ ├── commands.ts │ │ │ │ │ ├── component-index.html │ │ │ │ │ └── component.ts │ │ │ │ └── tsconfig.cy.json │ │ │ ├── cypress.config.ts │ │ │ ├── cypress.d.ts │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── actions/ │ │ │ │ └── example.action.ts │ │ │ ├── components/ │ │ │ │ └── example/ │ │ │ │ ├── example.cy.tsx │ │ │ │ └── example.tsx │ │ │ └── loaders/ │ │ │ └── example.loader.ts │ │ ├── drizzle/ │ │ │ ├── drizzle/ │ │ │ │ ├── db/ │ │ │ │ │ └── .gitkeep │ │ │ │ ├── migrations/ │ │ │ │ │ └── .gitkeep │ │ │ │ └── schema.ts │ │ │ ├── drizzle.config.ts │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── routes/ │ │ │ ├── create/ │ │ │ │ └── index.tsx │ │ │ └── users/ │ │ │ ├── [userId]/ │ │ │ │ └── index.tsx │ │ │ └── index.tsx │ │ ├── leaflet-map/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── components/ │ │ │ │ └── leaflet-map/ │ │ │ │ └── index.tsx │ │ │ ├── helpers/ │ │ │ │ └── boundary-box.tsx │ │ │ ├── models/ │ │ │ │ ├── location.ts │ │ │ │ └── map.ts │ │ │ └── routes/ │ │ │ └── basic-map/ │ │ │ └── index.tsx │ │ ├── orama/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── orama/ │ │ │ │ └── index.ts │ │ │ └── routes/ │ │ │ └── orama/ │ │ │ └── index.tsx │ │ ├── pandacss/ │ │ │ ├── .eslintignore │ │ │ ├── .prettierignore │ │ │ ├── gitignore │ │ │ ├── package.json │ │ │ ├── panda.config.ts │ │ │ ├── postcss.config.js │ │ │ └── src/ │ │ │ ├── global.css │ │ │ └── routes/ │ │ │ └── pandacss/ │ │ │ └── index.tsx │ │ ├── partytown/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── components/ │ │ │ └── partytown/ │ │ │ └── partytown.tsx │ │ ├── playwright/ │ │ │ ├── package.json │ │ │ ├── playwright.config.ts │ │ │ └── tests/ │ │ │ └── example.spec.ts │ │ ├── postcss/ │ │ │ ├── .vscode/ │ │ │ │ └── settings.json │ │ │ ├── package.json │ │ │ └── postcss.config.js │ │ ├── prisma/ │ │ │ ├── package.json │ │ │ ├── prisma/ │ │ │ │ └── schema.prisma │ │ │ └── src/ │ │ │ └── routes/ │ │ │ ├── create/ │ │ │ │ └── index.tsx │ │ │ └── users/ │ │ │ ├── [userId]/ │ │ │ │ └── index.tsx │ │ │ └── index.tsx │ │ ├── react/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ ├── integrations/ │ │ │ │ └── react/ │ │ │ │ └── mui.tsx │ │ │ └── routes/ │ │ │ └── react/ │ │ │ └── index.tsx │ │ ├── service-worker/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── routes/ │ │ │ └── service-worker.ts │ │ ├── storybook/ │ │ │ ├── .storybook/ │ │ │ │ ├── main.ts │ │ │ │ ├── preview-head.html │ │ │ │ ├── preview.tsx │ │ │ │ └── tsconfig.json │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── components/ │ │ │ └── button/ │ │ │ ├── button.stories.tsx │ │ │ └── button.tsx │ │ ├── styled-vanilla-extract/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── routes/ │ │ │ └── styled-flower/ │ │ │ ├── flower.css.ts │ │ │ └── index.tsx │ │ ├── tailwind/ │ │ │ ├── package.json │ │ │ ├── prettier.config.js │ │ │ └── src/ │ │ │ └── global.css │ │ ├── tailwind-v3/ │ │ │ ├── .vscode/ │ │ │ │ └── settings.json │ │ │ ├── package.json │ │ │ ├── postcss.config.cjs │ │ │ ├── prettier.config.js │ │ │ ├── src/ │ │ │ │ └── global.css │ │ │ └── tailwind.config.js │ │ ├── turso/ │ │ │ ├── package.json │ │ │ └── src/ │ │ │ └── utils/ │ │ │ └── turso.ts │ │ └── vitest/ │ │ ├── package.json │ │ └── src/ │ │ └── components/ │ │ └── example/ │ │ ├── example.spec.tsx │ │ └── example.tsx │ ├── playwright.config.ts │ └── templates/ │ ├── barrel/ │ │ ├── component/ │ │ │ └── index.tsx.template │ │ ├── markdown/ │ │ │ └── index.md.template │ │ ├── mdx/ │ │ │ └── index.mdx.template │ │ └── route/ │ │ └── index.tsx.template │ └── qwik/ │ ├── component/ │ │ └── [slug].tsx.template │ ├── markdown/ │ │ └── index.md.template │ ├── mdx/ │ │ └── index.mdx.template │ └── route/ │ └── index.tsx.template ├── syncpack-release-conf.json ├── tsconfig-docs.json ├── tsconfig.json ├── tsconfig.scripts.json ├── types.d.ts ├── vitest-setup.ts ├── vitest.config.ts └── vitest.workspace.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .all-contributorsrc ================================================ { "projectName": "qwik", "projectOwner": "QwikDev", "repoType": "github", "repoHost": "https://github.com", "files": ["README.md"], "imageSize": 100, "commit": true, "commitConvention": "angular", "contributors": [], "contributorsPerLine": 7 } ================================================ FILE: .changeset/breezy-items-relax.md ================================================ --- '@builder.io/qwik-city': patch --- FIX: When a form POST is done, keys like "name.1" mean it's an array. However, later keys could be strings like "name.value". Now, we check if all the keys are numbers, otherwise we make an object instead of an array. This allows for more correct form data handling. ================================================ FILE: .changeset/changelog-github-custom.cjs ================================================ 'use strict'; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function (t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator['throw'](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __generator = (this && this.__generator) || function (thisArg, body) { var _ = { label: 0, sent: function () { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [], }, f, y, t, g; return ( (g = { next: verb(0), throw: verb(1), return: verb(2) }), typeof Symbol === 'function' && (g[Symbol.iterator] = function () { return this; }), g ); function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError('Generator is already executing.'); while ((g && ((g = 0), op[0] && (_ = 0)), _)) try { if ( ((f = 1), y && (t = op[0] & 2 ? y['return'] : op[0] ? y['throw'] || ((t = y['return']) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) ) return t; if (((y = 0), t)) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if ( !((t = _.trys), (t = t.length > 0 && t[t.length - 1])) && (op[0] === 6 || op[0] === 2) ) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } }; var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); }; Object.defineProperty(exports, '__esModule', { value: true }); // @ts-ignore var get_github_info_1 = require('@changesets/get-github-info'); var dotenv_1 = require('dotenv'); (0, dotenv_1.config)(); var changelogFunctions = { getDependencyReleaseLine: function (changesets, dependenciesUpdated, options) { return __awaiter(void 0, void 0, void 0, function () { var changesetLink, _a, updatedDepenenciesList; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!options.repo) { throw new Error( 'Please provide a repo to this changelog generator like this:\n"changelog": ["@changesets/changelog-github", { "repo": "org/repo" }]' ); } if (dependenciesUpdated.length === 0) return [2 /*return*/, '']; _a = '- Updated dependencies ['.concat; return [ 4 /*yield*/, Promise.all( changesets.map(function (cs) { return __awaiter(void 0, void 0, void 0, function () { var links; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!cs.commit) return [3 /*break*/, 2]; return [ 4 /*yield*/, (0, get_github_info_1.getInfo)({ repo: options.repo, commit: cs.commit, }), ]; case 1: links = _a.sent().links; return [2 /*return*/, links.commit]; case 2: return [2 /*return*/]; } }); }); }) ), ]; case 1: changesetLink = _a.apply('- Updated dependencies [', [ _b .sent() .filter(function (_) { return _; }) .join(', '), ']:', ]); updatedDepenenciesList = dependenciesUpdated.map(function (dependency) { return ' - '.concat(dependency.name, '@').concat(dependency.newVersion); }); return [ 2 /*return*/, __spreadArray([changesetLink], updatedDepenenciesList, true).join('\n'), ]; } }); }); }, getReleaseLine: function (changeset, type, options) { return __awaiter(void 0, void 0, void 0, function () { var prFromSummary, commitFromSummary, usersFromSummary, replacedChangelog, linkifyIssueHints, _a, firstLine, futureLines, links, users, suffix, emojiFirstline; return __generator(this, function (_b) { switch (_b.label) { case 0: if (!options || !options.repo) { throw new Error( 'Please provide a repo to this changelog generator like this:\n"changelog": ["@changesets/changelog-github", { "repo": "org/repo" }]' ); } usersFromSummary = []; replacedChangelog = changeset.summary .replace(/^\s*(?:pr|pull|pull\s+request):\s*#?(\d+)/im, function (_, pr) { var num = Number(pr); if (!isNaN(num)) prFromSummary = num; return ''; }) .replace(/^\s*commit:\s*([^\s]+)/im, function (_, commit) { commitFromSummary = commit; return ''; }) .replace(/^\s*(?:author|user):\s*@?([^\s]+)/gim, function (_, user) { usersFromSummary.push(user); return ''; }) .trim(); linkifyIssueHints = function (line) { return line.replace( /(?<=\( ?(?:fix|fixes|see) )(#\d+)(?= ?\))/g, function (issueHash) { return '[' .concat(issueHash, '](https://github.com/') .concat(options.repo, '/issues/') .concat(issueHash.substring(1), ')'); } ); }; (_a = replacedChangelog.split('\n').map(function (l) { return linkifyIssueHints(l.trimEnd()); })), (firstLine = _a[0]), (futureLines = _a.slice(1)); return [ 4 /*yield*/, (function () { return __awaiter(void 0, void 0, void 0, function () { var links_1, shortCommitId, commitToFetchFrom, links_2; return __generator(this, function (_a) { switch (_a.label) { case 0: if (!(prFromSummary !== undefined)) return [3 /*break*/, 2]; return [ 4 /*yield*/, (0, get_github_info_1.getInfoFromPullRequest)({ repo: options.repo, pull: prFromSummary, }), ]; case 1: links_1 = _a.sent().links; if (commitFromSummary) { shortCommitId = commitFromSummary.slice(0, 7); links_1 = __assign(__assign({}, links_1), { commit: '[`' .concat(shortCommitId, '`](https://github.com/') .concat(options.repo, '/commit/') .concat(commitFromSummary, ')'), }); } return [2 /*return*/, links_1]; case 2: commitToFetchFrom = commitFromSummary || changeset.commit; if (!commitToFetchFrom) return [3 /*break*/, 4]; return [ 4 /*yield*/, (0, get_github_info_1.getInfo)({ repo: options.repo, commit: commitToFetchFrom, }), ]; case 3: links_2 = _a.sent().links; return [2 /*return*/, links_2]; case 4: return [ 2 /*return*/, { commit: null, pull: null, user: null, }, ]; } }); }); })(), ]; case 1: links = _b.sent(); users = usersFromSummary.length ? usersFromSummary .map(function (userFromSummary) { return '[@' .concat(userFromSummary, '](https://github.com/') .concat(userFromSummary, ')'); }) .join(', ') : links.user; suffix = ''; if (links.pull || links.commit || users) { suffix = '(' .concat(users ? 'by '.concat(users, ' ') : '', 'in ') .concat(links.pull || links.commit, ')'); } emojiFirstline = firstLine .replace(/feat:/i, '✨') .replace(/chore:/i, '🛠') .replace(/infra:/i, '🛠') .replace(/fix:/i, '🐞🩹') .replace(/docs:/i, '📃'); return [ 2 /*return*/, '\n\n- ' .concat(emojiFirstline, ' ') .concat(suffix, '\n') .concat( futureLines .map(function (l) { return ' '.concat(l); }) .join('\n') ), ]; } }); }); }, }; exports.default = changelogFunctions; ================================================ FILE: .changeset/changelog-github-custom.ts ================================================ import { ChangelogFunctions } from '@changesets/types'; // @ts-ignore import { getInfo, getInfoFromPullRequest } from '@changesets/get-github-info'; import { config } from 'dotenv'; config(); const changelogFunctions: ChangelogFunctions = { getDependencyReleaseLine: async (changesets, dependenciesUpdated, options) => { if (!options.repo) { throw new Error( 'Please provide a repo to this changelog generator like this:\n"changelog": ["@changesets/changelog-github", { "repo": "org/repo" }]' ); } if (dependenciesUpdated.length === 0) { return ''; } const changesetLink = `- Updated dependencies [${( await Promise.all( changesets.map(async (cs) => { if (cs.commit) { const { links } = await getInfo({ repo: options.repo, commit: cs.commit, }); return links.commit; } }) ) ) .filter((_) => _) .join(', ')}]:`; const updatedDepenenciesList = dependenciesUpdated.map( (dependency) => ` - ${dependency.name}@${dependency.newVersion}` ); return [changesetLink, ...updatedDepenenciesList].join('\n'); }, getReleaseLine: async (changeset, type, options) => { if (!options || !options.repo) { throw new Error( 'Please provide a repo to this changelog generator like this:\n"changelog": ["@changesets/changelog-github", { "repo": "org/repo" }]' ); } let prFromSummary: number | undefined; let commitFromSummary: string | undefined; const usersFromSummary: string[] = []; const replacedChangelog = changeset.summary .replace(/^\s*(?:pr|pull|pull\s+request):\s*#?(\d+)/im, (_, pr) => { const num = Number(pr); if (!isNaN(num)) { prFromSummary = num; } return ''; }) .replace(/^\s*commit:\s*([^\s]+)/im, (_, commit) => { commitFromSummary = commit; return ''; }) .replace(/^\s*(?:author|user):\s*@?([^\s]+)/gim, (_, user) => { usersFromSummary.push(user); return ''; }) .trim(); const linkifyIssueHints = (line: string) => line.replace(/(?<=\( ?(?:fix|fixes|see) )(#\d+)(?= ?\))/g, (issueHash) => { return `[${issueHash}](https://github.com/${ options.repo }/issues/${issueHash.substring(1)})`; }); const [firstLine, ...futureLines] = replacedChangelog .split('\n') .map((l) => linkifyIssueHints(l.trimEnd())); const links = await (async () => { if (prFromSummary !== undefined) { let { links } = await getInfoFromPullRequest({ repo: options.repo, pull: prFromSummary, }); if (commitFromSummary) { const shortCommitId = commitFromSummary.slice(0, 7); links = { ...links, commit: `[\`${shortCommitId}\`](https://github.com/${options.repo}/commit/${commitFromSummary})`, }; } return links; } const commitToFetchFrom = commitFromSummary || changeset.commit; if (commitToFetchFrom) { const { links } = await getInfo({ repo: options.repo, commit: commitToFetchFrom, }); return links; } return { commit: null, pull: null, user: null, }; })(); const users = usersFromSummary.length ? usersFromSummary .map((userFromSummary) => `[@${userFromSummary}](https://github.com/${userFromSummary})`) .join(', ') : links.user; let suffix = ''; if (links.pull || links.commit || users) { suffix = `(${users ? `by ${users} ` : ''}in ${links.pull || links.commit})`; } const emojiFirstline = firstLine .replace(/feat:/i, '✨') .replace(/chore:/i, '🛠') .replace(/infra:/i, '🛠') .replace(/fix:/i, '🐞🩹') .replace(/docs:/i, '📃'); return `\n\n- ${emojiFirstline} ${suffix}\n${futureLines.map((l) => ` ${l}`).join('\n')}`; }, }; export default changelogFunctions; ================================================ FILE: .changeset/config.json ================================================ { "$schema": "https://unpkg.com/@changesets/config@3.0.1/schema.json", "changelog": ["./changelog-github-custom.cjs", { "repo": "QwikDev/qwik" }], "commit": false, "fixed": [["@builder.io/qwik", "@builder.io/qwik-city", "eslint-plugin-qwik", "create-qwik"]], "linked": [], "access": "public", "baseBranch": "origin/upcoming", "updateInternalDependencies": "minor", "ignore": [ "qwik-docs", "@builder.io/qwik-labs", "insights", "@builder.io/qwik-worker", "qwik-cli-e2e", "qwik-react-test-app", "docs-e2e" ], "___experimentalUnsafeOptions_WILL_CHANGE_IN_PATCH": { "onlyUpdatePeerDependentsWhenOutOfRange": true } } ================================================ FILE: .changeset/deno-production-builds.md ================================================ --- '@builder.io/qwik': patch '@builder.io/qwik-city': patch --- FIX: support Deno as package manager for production builds. The Vite plugin now recognizes Deno as a Node-compatible runtime for manifest passing, and SSG delegates to the Node implementation instead of stubbing out. ================================================ FILE: .changeset/eager-sides-sit.md ================================================ --- '@builder.io/qwik': patch --- FIX: the optimizer was not using the binary builds ================================================ FILE: .changeset/fix-virtual-css-dev-ssr.md ================================================ --- '@builder.io/qwik': patch --- fix: resolve 404 error for virtual CSS modules during dev SSR ================================================ FILE: .changeset/late-parrots-open.md ================================================ --- 'eslint-plugin-qwik': patch --- Support ESLint v10 ================================================ FILE: .changeset/shaky-ends-help.md ================================================ --- '@builder.io/qwik-city': patch --- fix: Link hash change now properly updates location.url.hash ================================================ FILE: .changeset/small-candies-train.md ================================================ --- '@builder.io/qwik-city': patch --- fix: handle special characters in dynamic route ================================================ FILE: .changeset/smooth-ends-count.md ================================================ --- '@builder.io/qwik': patch --- fix: type casts to bridge Rollup vs Rolldown type differences without changing runtime behavior ================================================ FILE: .devcontainer/Dockerfile ================================================ FROM cimg/rust:1.88.0-node RUN rustup --version; \ cargo --version; \ rustc --version; RUN rustup update; \ rustup target add wasm32-unknown-unknown; \ cargo install cargo-insta --locked; \ cargo install wasm-pack --locked; \ rustup component add clippy; \ corepack enable --install-directory ~/bin RUN mkdir /home/circleci/store; \ pnpm config set store-dir /home/circleci/store ================================================ FILE: .devcontainer/devcontainer.json ================================================ // For format details, see https://aka.ms/devcontainer.json. For config options, see the README at: // https://github.com/microsoft/vscode-dev-containers/tree/v0.217.2/containers/docker-existing-dockerfile { "name": "Qwik devcontainer", "hostRequirements": { "cpus": 4 }, // Add the IDs of extensions you want installed when the container is created. "extensions": [ "esbenp.prettier-vscode", "rust-lang.rust-analyzer", "hdevalke.rust-test-lens", "ms-playwright.playwright", "manucorporat.vermoji", "ms-azuretools.vscode-docker", "mitsuhiko.insta", "silvenon.mdx", "csstools.postcss" ], "build": { "dockerfile": "Dockerfile" }, "waitFor": "updateContentCommand", "updateContentCommand": "corepack install && pnpm install", "forwardPorts": [3300, 9229], "customizations": { "codespaces": { "openFiles": ["CONTRIBUTING.md"] } }, "portsAttributes": { "3300": { "label": "Serve", "onAutoForward": "openPreview" } } } ================================================ FILE: .dockerignore ================================================ .history .vscode dist dist-dev node_modules tsc-out external *. **/*.log etc temp tsdoc-metadata.json **/.DS_Store integration/out/ integration/todo/output integration/*.js integration/*.cjs integration/*.map packages/qwik/src/napi/package-* target *.node todo-express/ qwik-app/ ================================================ FILE: .envrc ================================================ # shellcheck shell=bash use flake watch_file rust-toolchain ================================================ FILE: .gitattributes ================================================ *.json linguist-language=JSON-with-Comments .yarn/releases/** binary .yarn/plugins/** binary ================================================ FILE: .github/CODEOWNERS ================================================ # For all PRs * @QwikDev/core-veterans # For docs PRs packages/docs @QwikDev/docs-team @QwikDev/qwik-team contributing @QwikDev/docs-team @QwikDev/qwik-team README.md @QwikDev/docs-team @QwikDev/qwik-team CONTRIBUTING.md @QwikDev/docs-team @QwikDev/qwik-team CODE_OF_CONDUCT.md @QwikDev/docs-team @QwikDev/qwik-team # For API changes api.json @QwikDev/api-guards # For releases CHANGELOG.md @QwikDev/api-guards # Protect the code owners file .github/CODEOWNERS @mhevery @shairez ================================================ FILE: .github/ISSUE_TEMPLATE/bug.yaml ================================================ name: 🐞 Bug Report description: Something does not work or is flaky! let us know! labels: ['TYPE: bug', 'STATUS-1: needs triage'] title: '[🐞]' body: - type: markdown attributes: value: | Thanks for taking the time to fill out this bug report! - type: dropdown id: component attributes: label: Which component is affected? options: - Qwik Runtime - Qwik Rollup / Vite plugin - Qwik Optimizer (rust) - Qwik React - Qwik City (routing) - Starters / CLI - Qwik Playground validations: required: true - type: textarea id: description attributes: description: 'A clear and concise description of what you expected to happen instead. If you intend to submit a PR for this issue, tell us in the description. Thanks!' label: Describe the bug placeholder: I am doing ... What I expect is ... What actually happening is ... validations: required: true - type: input id: reproduction attributes: label: Reproduction description: Please provide a link via [qwik.new](https://qwik.new/) or a link to a repo that can reproduce the problem you ran into. `npm create qwik@latest` can be used as a starter template. A [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) is required ([Why?](https://antfu.me/posts/why-reproductions-are-required)). If a report is vague (e.g. just a generic error message) and has no reproduction, it will receive a "need reproduction" label. If no reproduction is provided after 3 days, it will be auto-closed. placeholder: Reproduction URL validations: required: true - type: textarea id: reproduction-steps attributes: label: Steps to reproduce description: Please provide any reproduction steps that may need to be described. E.g. if it happens only when running the dev or build script make sure it's clear which one to use. placeholder: Run `npm install` followed by `npm run dev` - type: textarea id: system-info attributes: label: System Info description: Output of `npx envinfo --system --npmPackages '{vite,undici,typescript,@builder.io/*}' --binaries --browsers` render: shell placeholder: System, Binaries, Browsers validations: required: true - type: textarea id: additional_information attributes: label: Additional Information validations: required: false ================================================ FILE: .github/ISSUE_TEMPLATE/config.yml ================================================ contact_links: - name: ✨ Feature requests Ideas url: https://github.com/QwikDev/qwik-evolution/discussions about: Propose new features and improvements and help shape Qwik - name: 🤔 Support Question url: https://qwik.dev/chat about: This issue tracker is not for support questions. Please post your question on the Discord chat. ================================================ FILE: .github/ISSUE_TEMPLATE/docs_suggestion.yml ================================================ name: 📖 Documentation Suggestion description: Suggestions on how we can improve the documentation. title: '[📖]' labels: ['COMP: docs', 'STATUS-1: needs triage'] body: - type: markdown attributes: value: | Thanks for taking the time to fill out docs suggestion! However, if you think it's something you can fix yourself, please submit a PR instead. In every doc page, you will be able to find the "Edit this page" in the right menu! ![Screenshot](https://user-images.githubusercontent.com/127379/203278116-7986d8b2-6aad-45fd-9890-7f171ca26bf0.png) - type: textarea id: description attributes: description: 'A clear and concise description of your suggestion to improve the docs.' label: Suggestion validations: required: true ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ # What is it? - Feature / enhancement - Bug - Docs / tests / types / typos - Infra # Description # Checklist - [ ] My code follows the [developer guidelines of this project](https://github.com/QwikDev/qwik/blob/main/CONTRIBUTING.md) - [ ] I performed a self-review of my own code - [ ] I added a changeset with `pnpm change` - [ ] I made corresponding changes to the Qwik docs - [ ] I added new tests to cover the fix / functionality ================================================ FILE: .github/workflows/ai-issue-triage.yml ================================================ name: AI Issue Triage on: issues: types: [opened] permissions: issues: write jobs: triage: if: github.repository == 'QwikDev/qwik' runs-on: ubuntu-latest steps: - name: Check account age (skip accounts < 30 days) id: check uses: actions/github-script@v7 with: script: | const user = await github.rest.users.getByUsername({ username: context.payload.issue.user.login }); const created = new Date(user.data.created_at); const days = (Date.now() - created) / (1000 * 60 * 60 * 24); return days >= 30; - name: AI triage and apply labels if: steps.check.outputs.result == 'true' uses: actions/github-script@v7 env: OPENCODE_API_KEY: ${{ secrets.OPENCODE_API_KEY }} with: script: | const issue = context.payload.issue; const issueText = `Title: ${issue.title}\n\nBody: ${issue.body || '(empty)'}`; // Call OpenCode Zen API (OpenAI-compatible) const response = await fetch('https://opencode.ai/zen/v1/chat/completions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${process.env.OPENCODE_API_KEY}` }, body: JSON.stringify({ model: 'kimi-k2.5', messages: [ { role: 'system', content: `You are a Qwik framework issue triager. Given an issue, respond with ONLY a JSON array of label strings to apply. No explanation, no markdown, just the JSON array. Available labels: Type (pick exactly one): - "bug" — Something isn't working - "enhancement" — New feature or request Component (pick if clearly relevant): - "runtime", "Optimizer", "Router", "SSR", "Preloader", "starters", "styling", "types", "reactivity", "Insights", "docs", "DX" Status (apply if applicable): - "needs reproduction" — Bug report lacks a reproduction link Rules: 1. Always include exactly ONE type label. 2. For bugs without a reproduction link, include "needs reproduction". 3. Do NOT include "good first issue" unless the fix is obviously trivial. 4. Respond with ONLY a JSON array like: ["bug", "runtime", "needs reproduction"]` }, { role: 'user', content: issueText } ], temperature: 0 }) }); if (!response.ok) { const text = await response.text(); core.setFailed(`Zen API error ${response.status}: ${text}`); return; } const data = await response.json(); const content = data.choices[0].message.content.trim(); // Parse labels from response let labels; try { labels = JSON.parse(content); } catch { // Try extracting JSON array from response const match = content.match(/\[[\s\S]*\]/); if (match) { labels = JSON.parse(match[0]); } else { core.setFailed(`Could not parse labels from: ${content}`); return; } } if (!Array.isArray(labels) || labels.length === 0) { core.setFailed(`Invalid labels response: ${content}`); return; } // Fetch actual repo labels to validate against const repoLabels = await github.paginate(github.rest.issues.listLabelsForRepo, { owner: context.repo.owner, repo: context.repo.repo, per_page: 100 }); const allowed = new Set(repoLabels.map(l => l.name)); const valid = labels.filter(l => allowed.has(l)); if (valid.length === 0) { core.setFailed(`No valid labels found in: ${JSON.stringify(labels)}`); return; } // Apply labels await github.rest.issues.addLabels({ owner: context.repo.owner, repo: context.repo.repo, issue_number: issue.number, labels: valid }); core.info(`Applied labels: ${valid.join(', ')}`); // Post follow-up comment for needs reproduction // (labeling-issues.yml won't fire because GITHUB_TOKEN labels don't trigger labeled events) if (valid.includes('needs reproduction')) { const author = issue.user.login; await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, issue_number: issue.number, body: `Hello @${author}. Please provide a [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) using a GitHub repository or [StackBlitz](https://qwik.new).\n[Here](https://antfu.me/posts/why-reproductions-are-required#why-reproduction) is why reproductions help us fix issues faster.\nThanks 🙏` }); } ================================================ FILE: .github/workflows/auto-assign-core-team.yml ================================================ name: Auto-assign PRs to core team authors on: pull_request_target: types: [opened, reopened, ready_for_review, converted_to_draft] permissions: pull-requests: write contents: read jobs: auto_assign: name: Assign PR author when core team member runs-on: ubuntu-latest steps: - name: Check team membership via REST id: team env: GH_TOKEN: ${{ secrets.QWIK_AUTO_ASSIGN_PR_PAT }} ORG: QwikDev TEAM_SLUG: qwik-team AUTHOR: ${{ github.event.pull_request.user.login }} run: | RESPONSE=$(curl -s \ -H "Authorization: token ${GH_TOKEN}" \ -H "Accept: application/vnd.github+json" \ "https://api.github.com/orgs/${ORG}/teams/${TEAM_SLUG}/memberships/${AUTHOR}") STATE=$(echo "$RESPONSE" | jq -r '.state // empty') if [ "$STATE" = "active" ]; then echo "isCore=true" >> $GITHUB_OUTPUT else echo "isCore=false" >> $GITHUB_OUTPUT fi - name: Assign PR to author if: steps.team.outputs.isCore == 'true' env: GH_TOKEN: ${{ secrets.QWIK_AUTO_ASSIGN_PR_PAT }} run: | PR_NUMBER=${{ github.event.pull_request.number }} AUTHOR=${{ github.event.pull_request.user.login }} curl -s -H "Authorization: token ${GH_TOKEN}" \ -H "Accept: application/vnd.github+json" \ -X POST \ -d "{\"assignees\":[\"${AUTHOR}\"]}" \ https://api.github.com/repos/${{ github.repository }}/issues/${PR_NUMBER}/assignees - name: Add PR to Qwik Development project id: add-project if: steps.team.outputs.isCore == 'true' uses: actions/add-to-project@v1.0.2 with: project-url: https://github.com/orgs/QwikDev/projects/1 github-token: ${{ secrets.QWIK_AUTO_ASSIGN_PR_PAT }} - name: Set status to "In progress" (draft) if: steps.team.outputs.isCore == 'true' && github.event.pull_request.draft == true uses: titoportas/update-project-fields@v0.1.0 with: project-url: https://github.com/orgs/QwikDev/projects/1 github-token: ${{ secrets.QWIK_AUTO_ASSIGN_PR_PAT }} item-id: ${{ steps.add-project.outputs.itemId }} field-keys: Status field-values: In progress - name: Set status to "Waiting For Review" (ready) if: steps.team.outputs.isCore == 'true' && github.event.pull_request.draft == false uses: titoportas/update-project-fields@v0.1.0 with: project-url: https://github.com/orgs/QwikDev/projects/1 github-token: ${{ secrets.QWIK_AUTO_ASSIGN_PR_PAT }} item-id: ${{ steps.add-project.outputs.itemId }} field-keys: Status field-values: Waiting For Review ================================================ FILE: .github/workflows/bench.yml.disabled ================================================ # disabled for now, not working as expected and not checking qwik runtime performance name: Benchmark on: - push - pull_request jobs: changes: runs-on: ubuntu-latest outputs: optimizer: ${{ steps.filter.outputs.optimizer }} steps: - uses: actions/checkout@v5 - uses: dorny/paths-filter@v2 id: filter with: filters: | optimizer: - 'src/optimizer/core/**' benchmark: name: Performance regression check needs: changes if: ${{ needs.changes.outputs.optimizer == 'true' }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 - name: Cache uses: actions/cache@v4 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ target/ key: cargo-bench-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} restore-keys: | cargo-bench-${{ runner.os }}-${{ hashFiles('**/Cargo.lock') }} - name: Install Rust uses: actions-rs/toolchain@v1 with: profile: minimal toolchain: nightly-2021-09-30 override: true - name: Run benchmark run: cargo +nightly-2021-09-30 bench --workspace | tee output.txt - name: Download previous benchmark results run: mkdir raw-data && curl -o raw-data/benchmark-data.json https://raw.githubusercontent.com/QwikDev/qwik-raw-data/gh-pages/benchmark-data.json - name: Analyze benchmark result uses: benchmark-action/github-action-benchmark@v1 with: # What benchmark tool the output.txt came from tool: 'cargo' # Where the output from the benchmark tool is stored output-file-path: output.txt external-data-json-path: ./raw-data/${{ github.sha }}/benchmark-data.json # Workflow will fail when an alert happens fail-on-alert: false # GitHub API token to make a commit comment github-token: ${{ secrets.GITHUB_TOKEN }} # Enable alert commit comment comment-on-alert: true comment-always: true alert-comment-cc-users: '@manucorporat' skip-fetch-gh-pages: true - name: Analyze benchmark result (root) if: ${{ github.event_name == 'push' }} uses: benchmark-action/github-action-benchmark@v1 with: # What benchmark tool the output.txt came from tool: 'cargo' # Where the output from the benchmark tool is stored output-file-path: output.txt external-data-json-path: ./raw-data/benchmark-data.json # Workflow will fail when an alert happens # fail-on-alert: true # GitHub API token to make a commit comment github-token: ${{ secrets.GITHUB_TOKEN }} # Enable alert commit comment comment-on-alert: true comment-always: true alert-comment-cc-users: '@manucorporat' max-items-in-chart: 250 skip-fetch-gh-pages: true auto-push: false - name: Deploy to qwik-raw-data if: ${{ github.ref == 'refs/heads/main' }} uses: JamesIves/github-pages-deploy-action@4.1.0 with: token: ${{ secrets.PAT_GITHUB_TOKEN }} branch: gh-pages folder: raw-data clean: false single-commit: false git-config-email: github-bot@builder.io repository-name: QwikDev/qwik-raw-data commit-message: 'Update' ================================================ FILE: .github/workflows/ci.yml ================================================ # Build and test everything # # First it builds the packages and stores them in artifacts/cache. # Meanwhile it lints the code. # Then it runs the unit tests with the artifacts, as well as builds the docs and insights # Once it all works, it does a release # # NOTE: only use pnpm run scripts for build commands # This way we're sure that dev and CI environments are consistent name: Qwik CI # TODO fix e2e tests hanging and not cancelling # # We only need one instance of the workflow running at a time, per branch # concurrency: # group: ${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }} # cancel-in-progress: true on: pull_request: push: branches: - main - upcoming - next - qwik-labs - vercelserverless - 'build/**' workflow_dispatch: inputs: disttag: description: 'Publish "@builder.io/qwik" to NPM using this dist-tag, push the git-tag to the repo and create a GitHub release. The "latest" and "next" dist-tags will use the version number already committed in package.json.' required: true type: choice default: 'dev' options: - dev - next - latest env: # Disable incremental build, speeds up CI CARGO_INCREMENTAL: 0 permissions: id-token: write contents: write pull-requests: write jobs: changes: name: Setup runs-on: ubuntu-latest outputs: hash-qwik: ${{ steps.cache-qwik.outputs.cache-primary-key }} hash-rust: ${{ steps.cache-rust.outputs.cache-primary-key }} hash-others: ${{ steps.cache-others.outputs.cache-primary-key }} hash-docs: ${{ steps.cache-docs.outputs.cache-primary-key }} hash-insights: ${{ steps.cache-insights.outputs.cache-primary-key }} hash-unit: ${{ steps.cache-unit.outputs.cache-primary-key }} hash-e2e: ${{ steps.cache-e2e.outputs.cache-primary-key }} hash-cli-e2e: ${{ steps.cache-cli-e2e.outputs.cache-primary-key }} build-qwik: ${{ steps.cache-qwik.outputs.cache-hit != 'true' }} build-rust: ${{ steps.cache-rust.outputs.cache-hit != 'true' }} build-others: ${{ steps.cache-others.outputs.cache-hit != 'true' }} build-docs: ${{ steps.cache-docs.outputs.cache-hit != 'true' }} build-insights: ${{ steps.cache-insights.outputs.cache-hit != 'true' }} build-unit: ${{ steps.cache-unit.outputs.cache-hit != 'true' }} build-e2e: ${{ steps.cache-e2e.outputs.cache-hit != 'true' }} build-cli-e2e: ${{ steps.cache-cli-e2e.outputs.cache-hit != 'true' }} disttag: ${{ steps.set_dist_tag.outputs.disttag }} steps: - name: Branch run: echo "${{ github.ref }}" - name: NPM Dist Tag from input run: echo "${{ github.event.inputs.disttag }}" - name: Github event run: echo event_name=${{ github.event_name }} - name: Checkout uses: actions/checkout@v5 - name: Set Dist Tag id: set_dist_tag if: | github.ref == 'refs/heads/upcoming' && ( github.event_name == 'push' || github.event_name == 'workflow_dispatch' ) run: | if [ ${{ github.event_name }} == 'workflow_dispatch' ]; then disttag="${{ github.event.inputs.disttag }}" echo "Overriding disttag with input: $disttag" echo "disttag=${disttag}" >> $GITHUB_OUTPUT exit 0 fi is_release=false commit_id=${{ github.sha }} owner=${{ github.repository_owner }} repo=${{ github.event.repository.name }} removed_files=$(curl -s -H "Authorization: token ${{ secrets.GITHUB_TOKEN }}" \ "https://api.github.com/repos/$owner/$repo/commits/$commit_id" | jq -r '.files[] | select(.status == "removed") | .filename') echo "Removed files: $removed_files" md_file_removed=false for file in $removed_files; do if [[ $file == .changeset/*.md ]]; then md_file_removed=true break fi done if [ $md_file_removed = true ]; then if ! ls .changeset/*.md > /dev/null 2>&1; then is_release=true fi fi echo "is_release: $is_release" if [ "$is_release" = true ]; then disttag='latest' else disttag="${{github.event.inputs.disttag}}" fi echo "disttag: $disttag" echo "disttag=${disttag}" >> $GITHUB_OUTPUT - run: jq .scripts package.json > scripts.json - name: 'check cache: qwik' id: cache-qwik uses: actions/cache/restore@v4 with: lookup-only: true path: packages/qwik/dist # Note that this includes the package.json of qwik key: ${{ hashfiles('.github/workflows/ci.yml', 'pnpm-lock.yaml', 'scripts.json', 'scripts/**/*', 'packages/qwik/**/*', 'starters/features/**/*', 'starters/adapters/**/*', 'starters/templates/**/*', '!**/*.unit.*', '!**/*.rs', '!starters/apps/e2e') }} - run: 'echo ${{ steps.cache-qwik.outputs.cache-primary-key }} > qwik-key.txt' - name: 'check cache: rust' id: cache-rust uses: actions/cache/restore@v4 with: lookup-only: true path: packages/qwik/bindings key: ${{ hashfiles('Makefile', 'rust-toolchain', '**/Cargo.toml', '**/Cargo.lock', '**/*.rs') }} - run: 'echo ${{ steps.cache-rust.outputs.cache-primary-key }} > rust-key.txt' - name: 'check cache: others' id: cache-others uses: actions/cache/restore@v4 with: lookup-only: true path: | packages/qwik-city/lib packages/qwik-labs/lib packages/qwik-labs/vite packages/qwik-react/lib packages/eslint-plugin-qwik/dist packages/create-qwik/dist # note that all inputs need to be listed here, including qwik, for correct cache invalidation key: ${{ hashfiles('qwik-key.txt', 'rust-key.txt', 'packages/qwik-city/**/*', 'packages/qwik-labs/**/*', 'packages/qwik-react/**/*', 'packages/eslint-plugin-qwik/**/*', 'packages/create-qwik/**/*', 'starters/apps/**/*', '!**/*.unit.*') }} - run: 'echo ${{ steps.cache-others.outputs.cache-primary-key }} > others-key.txt' - name: 'check cache: docs' id: cache-docs uses: actions/cache/restore@v4 with: lookup-only: true path: docs-build-completed.txt key: ${{ hashfiles('others-key.txt', 'packages/docs/**/*') }} - name: 'check cache: insights' id: cache-insights uses: actions/cache/restore@v4 with: lookup-only: true path: | packages/insights/dist packages/insights/.netlify key: ${{ hashfiles('others-key.txt', 'packages/insights/**/*') }} - name: 'check cache: unit tests' id: cache-unit uses: actions/cache/restore@v4 with: lookup-only: true path: unit-tests-completed.txt key: ${{ hashfiles('others-key.txt', 'packages/**/*.unit.*') }} - name: 'check cache: e2e tests' id: cache-e2e uses: actions/cache/restore@v4 with: lookup-only: true path: e2e-tests-completed.txt key: ${{ hashfiles('others-key.txt', 'starters/**/*') }} - name: 'check cache: cli e2e tests' id: cache-cli-e2e uses: actions/cache/restore@v4 with: lookup-only: true path: cli-e2e-tests-completed.txt key: ${{ hashfiles('others-key.txt', 'e2e/**/*') }} ############ BUILD Qwik ############ build-qwik: if: needs.changes.outputs.build-qwik == 'true' name: Build Qwik needs: changes runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v5 - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v5 with: node-version: 24.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ - name: Install NPM Dependencies run: | # Ensure that the qwik binary gets made mkdir -p packages/qwik/bindings/ pnpm install --frozen-lockfile - name: 'build: qwik' run: pnpm build --qwik --set-dist-tag="${{ needs.changes.outputs.disttag }}" - name: Print Qwik Dist Build continue-on-error: true run: tree -a packages/qwik/dist/ - name: Save qwik cache uses: actions/cache/save@v4 with: key: ${{ needs.changes.outputs.hash-qwik }} path: packages/qwik/dist - name: Save artifacts uses: actions/upload-artifact@v4 with: name: artifact-qwik-no-optimizer include-hidden-files: true path: packages/qwik/dist/ if-no-files-found: error ############ BUILD PLATFORM BINDINGS ############ build-bindings: if: needs.changes.outputs.build-rust == 'true' strategy: matrix: settings: - host: ubuntu-latest target: x86_64-unknown-linux-gnu wasm: true # the last x86 macos available as a standard runner - host: macos-13 target: x86_64-apple-darwin - host: macos-latest target: aarch64-apple-darwin - host: windows-latest target: x86_64-pc-windows-msvc name: Build optimizer ${{ matrix.settings.target }} runs-on: ${{ matrix.settings.host }} needs: changes steps: - name: Checkout uses: actions/checkout@v5 - name: Install Rust toolchain uses: actions-rust-lang/setup-rust-toolchain@v1 with: components: clippy,rustfmt - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v5 with: node-version: 24.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ - run: pnpm install - if: matrix.settings.wasm run: pnpm install -w wasm-pack - name: Lint check if: matrix.settings.wasm run: pnpm lint.rust - name: Unit tests if: matrix.settings.wasm run: pnpm test.rust - name: Build Platform Binding run: pnpm build --platform-binding - name: Build Wasm Binding if: matrix.settings.wasm run: pnpm build --wasm - name: Print Packages Dist Build continue-on-error: true run: ls -lR packages/qwik/bindings/ - name: Upload Platform Binding Artifact uses: actions/upload-artifact@v4 with: name: artifact-bindings-${{ matrix.settings.target }} include-hidden-files: true path: packages/qwik/bindings/ if-no-files-found: error ############ BUILD PACKAGE ############ combined-qwik: name: Bundle Qwik if: always() runs-on: ubuntu-latest needs: - build-qwik - build-bindings - changes steps: - name: Verify builds if: | !( (needs.build-qwik.result == 'success' || needs.build-qwik.result == 'skipped') && (needs.build-bindings.result == 'success' || needs.build-bindings.result == 'skipped') ) run: exit 1 - name: Restore artifacts if: needs.changes.outputs.build-rust == 'true' uses: actions/download-artifact@v4 - name: Restore Qwik from cache uses: actions/cache/restore@v4 with: path: packages/qwik/dist key: ${{ needs.changes.outputs.hash-qwik }} - name: Restore Rust from cache if: needs.changes.outputs.build-rust != 'true' uses: actions/cache/restore@v4 with: path: packages/qwik/bindings key: ${{ needs.changes.outputs.hash-rust }} - name: Move Rust Artifacts if: needs.changes.outputs.build-rust == 'true' run: | mkdir -p packages/qwik/bindings mv artifact-bindings-*/* packages/qwik/bindings - name: Save rust cache if: needs.changes.outputs.build-rust == 'true' uses: actions/cache/save@v4 with: key: ${{ needs.changes.outputs.hash-rust }} path: packages/qwik/bindings - name: Upload Qwik artifact uses: actions/upload-artifact@v4 with: name: artifact-qwik include-hidden-files: true path: | packages/qwik/bindings packages/qwik/dist if-no-files-found: error build-other-packages: name: Build Other Packages needs: - changes - combined-qwik if: always() runs-on: ubuntu-latest steps: - name: Verify combined-qwik if: needs.combined-qwik.result != 'success' run: exit 1 - name: Checkout if: needs.changes.outputs.build-others == 'true' uses: actions/checkout@v5 - uses: pnpm/action-setup@v4 if: needs.changes.outputs.build-others == 'true' - name: Setup Node if: needs.changes.outputs.build-others == 'true' uses: actions/setup-node@v5 with: node-version: 24.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ - name: Restore Qwik artifact uses: actions/download-artifact@v4 with: name: artifact-qwik path: packages/qwik/ - name: Install NPM Dependencies if: needs.changes.outputs.build-others == 'true' run: pnpm install - name: 'build: qwik-city & others' if: needs.changes.outputs.build-others == 'true' run: pnpm build --tsc --api --qwikcity --cli --qwiklabs --qwikreact --eslint --set-dist-tag="${{ needs.changes.outputs.disttag }}" - name: Save others cache if: needs.changes.outputs.build-others == 'true' uses: actions/cache/save@v4 with: key: ${{ needs.changes.outputs.hash-others }} path: | packages/qwik-city/lib packages/qwik-labs/lib packages/qwik-labs/vite packages/qwik-react/lib packages/eslint-plugin-qwik/dist packages/create-qwik/dist - name: 'restore: qwik-city & others' if: needs.changes.outputs.build-others != 'true' uses: actions/cache/restore@v4 with: path: | packages/qwik-city/lib packages/qwik-labs/lib packages/qwik-labs/vite packages/qwik-react/lib packages/eslint-plugin-qwik/dist packages/create-qwik/dist key: ${{ needs.changes.outputs.hash-others }} - name: Print QwikCity Lib Build run: tree -a packages/qwik-city/lib/ - name: Upload QwikCity Build Artifacts uses: actions/upload-artifact@v4 with: name: artifact-qwikcity include-hidden-files: true path: packages/qwik-city/lib/ if-no-files-found: error - name: Print QwikLabs Lib Build run: tree -a packages/qwik-labs/lib/ packages/qwik-labs/vite/ - name: Upload QwikLabs+React Build Artifacts uses: actions/upload-artifact@v4 with: name: artifact-qwiklabs include-hidden-files: true path: | packages/qwik-labs/lib/ packages/qwik-labs/vite/ packages/qwik-labs/package.json if-no-files-found: error - name: Print qwik-react Lib Build run: tree -a packages/qwik-react/lib/ - name: Upload qwik-react Build Artifacts uses: actions/upload-artifact@v4 with: name: artifact-qwikreact include-hidden-files: true path: | packages/qwik-react/lib/ packages/qwik-react/package.json if-no-files-found: error - name: Print Create Qwik CLI Dist Build run: tree -a packages/create-qwik/dist/ - name: Upload Create Qwik CLI Build Artifacts uses: actions/upload-artifact@v4 with: name: artifact-create-qwik include-hidden-files: true path: packages/create-qwik/dist/ if-no-files-found: error - name: Print Eslint rules Dist Build run: tree -a packages/eslint-plugin-qwik/dist/ - name: Upload Eslint rules Build Artifacts uses: actions/upload-artifact@v4 with: name: artifact-eslint-plugin-qwik include-hidden-files: true path: packages/eslint-plugin-qwik/dist/ if-no-files-found: error ############ BUILD INSIGHTS ############ build-insights: if: always() && needs.changes.outputs.build-insights == 'true' name: Build Insights needs: - changes - build-other-packages runs-on: ubuntu-latest steps: - name: Verify build-other-packages if: needs.build-other-packages.result != 'success' run: exit 1 - name: Checkout uses: actions/checkout@v5 - name: Download Build Artifacts uses: actions/download-artifact@v4 - name: Move Distribution Artifacts run: | mv artifact-qwik/* packages/qwik/ mkdir -p packages/qwik-city/lib/ mv artifact-qwikcity/* packages/qwik-city/lib/ mkdir -p packages/create-qwik/dist/ mv artifact-create-qwik/* packages/create-qwik/dist/ mkdir -p packages/eslint-plugin-qwik/dist/ mv artifact-eslint-plugin-qwik/* packages/eslint-plugin-qwik/dist/ mv artifact-qwiklabs/lib packages/qwik-labs/lib mv artifact-qwiklabs/vite packages/qwik-labs/vite - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v5 with: node-version: 24.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ - run: pnpm install --frozen-lockfile - name: Build Qwik Insights run: pnpm run build.packages.insights - name: Save Insights Cache uses: actions/cache/save@v4 with: key: ${{ needs.changes.outputs.hash-insights }} path: | packages/insights/dist packages/insights/.netlify ############ BUILD DOCS ############ build-docs: if: always() && needs.changes.outputs.build-docs == 'true' name: Build Docs needs: - changes - build-other-packages runs-on: ubuntu-latest steps: - name: Verify build-other-packages if: needs.build-other-packages.result != 'success' run: exit 1 - name: Checkout uses: actions/checkout@v5 - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v5 with: node-version: 24.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ - name: Download Build Artifacts uses: actions/download-artifact@v4 - name: Move Distribution Artifacts run: | mv artifact-qwik/* packages/qwik/ mkdir -p packages/qwik-city/lib/ mv artifact-qwikcity/* packages/qwik-city/lib/ mkdir -p packages/create-qwik/dist/ mv artifact-create-qwik/* packages/create-qwik/dist/ mkdir -p packages/eslint-plugin-qwik/dist/ mv artifact-eslint-plugin-qwik/* packages/eslint-plugin-qwik/dist/ mv artifact-qwiklabs/lib packages/qwik-labs/lib mv artifact-qwiklabs/vite packages/qwik-labs/vite mv artifact-qwikreact/lib packages/qwik-react/lib - run: pnpm install --frozen-lockfile - name: Build Qwik Docs run: pnpm run build.packages.docs && echo ok > docs-build-completed.txt - name: Save Docs Artifacts uses: actions/upload-artifact@v4 with: name: artifact-docs include-hidden-files: true path: | packages/docs/dist packages/docs/server - name: Save Docs Cache uses: actions/cache/save@v4 with: key: ${{ needs.changes.outputs.hash-docs }} path: docs-build-completed.txt ############ UNIT TEST ############ test-unit: name: Unit Tests if: always() && needs.changes.outputs.build-unit == 'true' runs-on: ubuntu-latest needs: - changes - build-other-packages steps: - name: Verify build-other-packages if: needs.build-other-packages.result != 'success' run: exit 1 - name: Checkout uses: actions/checkout@v5 - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v5 with: node-version: 24.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ - name: Download Build Artifacts uses: actions/download-artifact@v4 - name: Move Distribution Artifacts run: | mv artifact-qwik/* packages/qwik/ mkdir -p packages/qwik-city/lib/ mv artifact-qwikcity/* packages/qwik-city/lib/ mkdir -p packages/create-qwik/dist/ mv artifact-create-qwik/* packages/create-qwik/dist/ mkdir -p packages/eslint-plugin-qwik/dist/ mv artifact-eslint-plugin-qwik/* packages/eslint-plugin-qwik/dist/ - run: pnpm install --frozen-lockfile - name: Unit Tests run: pnpm run test.unit && echo ok > unit-tests-completed.txt - name: Save unit tests cache uses: actions/cache/save@v4 with: key: ${{ needs.changes.outputs.hash-unit }} path: unit-tests-completed.txt ############ E2E TEST ############ test-e2e: # Sometimes the tests just hang timeout-minutes: 20 name: E2E Tests if: always() && needs.changes.outputs.build-e2e == 'true' needs: - build-other-packages - changes - test-unit strategy: matrix: settings: - host: ubuntu-latest browser: chromium # too slow and flaky. Perhaps better in v2? # - host: ubuntu-latest # browser: firefox - host: macos-latest browser: webkit - host: windows-latest browser: chromium runs-on: ${{ matrix.settings.host }} steps: - name: Checkout uses: actions/checkout@v5 - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v5 with: node-version: 24.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ - name: Download Build Artifacts uses: actions/download-artifact@v4 - name: Move Distribution Artifacts run: | mv artifact-qwik/* packages/qwik/ mkdir -p packages/qwik-city/lib/ mv artifact-qwikcity/* packages/qwik-city/lib/ mkdir -p packages/create-qwik/dist/ mv artifact-create-qwik/* packages/create-qwik/dist/ mkdir -p packages/eslint-plugin-qwik/dist/ mv artifact-eslint-plugin-qwik/* packages/eslint-plugin-qwik/dist/ mkdir -p packages/qwik-react/lib/ mv artifact-qwikreact/lib/* packages/qwik-react/lib/ - run: pnpm install --frozen-lockfile - name: Install Playwright run: npx playwright install ${{ matrix.settings.browser }} --with-deps - name: Playwright E2E Tests run: pnpm run test.e2e.${{ matrix.settings.browser }} --timeout 60000 --retries 7 --workers 1 - name: Playwright E2E Integration Tests run: pnpm run test.e2e.integrations.${{ matrix.settings.browser }} --timeout 60000 --retries 7 --workers 1 - name: Playwright E2E Qwik React Tests run: pnpm run test.e2e.qwik-react.${{ matrix.settings.browser }} --timeout 60000 --retries 7 --workers 1 - name: Validate Create Qwik Cli if: matrix.settings.host != 'windows-latest' run: pnpm cli.validate ############ E2E CLI TEST ############ test-cli-e2e: name: E2E CLI Tests if: always() && needs.changes.outputs.build-cli-e2e == 'true' needs: - build-other-packages - changes - test-unit strategy: matrix: settings: - host: ubuntu-latest - host: macos-latest - host: windows-latest runs-on: ${{ matrix.settings.host }} steps: - name: Checkout uses: actions/checkout@v5 - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v5 with: node-version: 24.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ - name: Download Build Artifacts uses: actions/download-artifact@v4 - name: Move Distribution Artifacts run: | mv artifact-qwik/* packages/qwik/ mkdir -p packages/qwik-city/lib/ mv artifact-qwikcity/* packages/qwik-city/lib/ mkdir -p packages/create-qwik/dist/ mv artifact-create-qwik/* packages/create-qwik/dist/ mkdir -p packages/eslint-plugin-qwik/dist/ mv artifact-eslint-plugin-qwik/* packages/eslint-plugin-qwik/dist/ - run: pnpm install --frozen-lockfile - name: CLI E2E Tests run: pnpm run test.e2e.cli ########### LINT PACKAGES ############ lint-package: name: Lint Package runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v5 - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v5 with: node-version: 24.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ - run: pnpm install --frozen-lockfile - name: SyncPack Check if: always() run: pnpm run lint.syncpack - name: Prettier Check if: always() run: pnpm run lint.prettier - name: Build ESLint if: always() run: pnpm build --eslint - name: ESLint Check if: always() run: pnpm run lint.eslint ############ RELEASE ############ release: name: Release runs-on: ubuntu-latest needs: - changes - test-unit - test-e2e - test-cli-e2e # test-unit runs when any packages changes, so we have to release # on "upcoming", we always check if we have something to release # don't run on forks if: | always() && github.repository == 'QwikDev/qwik' && ( github.ref == 'refs/heads/upcoming' || needs.test-unit.result == 'success' || needs.test-unit.result == 'skipped' ) steps: - name: Verify test-e2e if: needs.test-e2e.result != 'skipped' run: | if [ "${{ needs.test-e2e.result }}" != success ] ; then exit 1 else echo ok > e2e-tests-completed.txt fi - name: Save e2e tests cache if: needs.test-e2e.result != 'skipped' uses: actions/cache/save@v4 with: key: ${{ needs.changes.outputs.hash-e2e }} path: e2e-tests-completed.txt - name: Verify test-cli-e2e if: needs.test-cli-e2e.result != 'skipped' run: | if [ "${{ needs.test-cli-e2e.result }}" != success ] ; then exit 1 else echo ok > cli-e2e-tests-completed.txt fi - name: Save cli-e2e tests cache if: needs.test-cli-e2e.result != 'skipped' uses: actions/cache/save@v4 with: key: ${{ needs.changes.outputs.hash-cli-e2e }} path: cli-e2e-tests-completed.txt - name: Checkout uses: actions/checkout@v5 - uses: pnpm/action-setup@v4 - name: Setup Node uses: actions/setup-node@v5 with: node-version: 24.x cache: 'pnpm' registry-url: https://registry.npmjs.org/ - name: Download Build Artifacts uses: actions/download-artifact@v4 - name: Move Distribution Artifacts run: | mv artifact-qwik/* packages/qwik/ mkdir -p packages/qwik-city/lib/ mv artifact-qwikcity/* packages/qwik-city/lib/ mkdir -p packages/create-qwik/dist/ mv artifact-create-qwik/* packages/create-qwik/dist/ mkdir -p packages/eslint-plugin-qwik/dist/ mv artifact-eslint-plugin-qwik/* packages/eslint-plugin-qwik/dist/ mv artifact-qwiklabs/lib packages/qwik-labs/lib mv artifact-qwiklabs/vite packages/qwik-labs/vite mv artifact-qwikreact/lib packages/qwik-react/lib rm -rf artifact-* - run: pnpm install --frozen-lockfile # Do this before other release steps to avoid # publishing temporary files - name: Create Release Pull Request or Publish to npm if: github.ref == 'refs/heads/upcoming' id: changesets uses: changesets/action@v1 with: publish: pnpm release env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Fixup package.json files run: pnpm run release.fixup-package-json - name: Commit Build Artifacts if: github.event_name == 'push' env: QWIK_API_TOKEN_GITHUB: ${{ secrets.QWIK_API_TOKEN_GITHUB }} run: pnpm run qwik-push-build-repos - name: Publish packages for testing if: github.event_name != 'workflow_dispatch' run: pnpm release.pkg-pr-new env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} ############ TRIGGER QWIKCITY E2E TEST ############ trigger-qwikcity-e2e: name: Trigger Qwik City E2E runs-on: ubuntu-latest if: github.ref == 'refs/heads/upcoming' needs: - changes - release steps: - name: Repository Dispatch uses: peter-evans/repository-dispatch@v2 with: token: ${{ secrets.QWIK_API_TOKEN_GITHUB }} repository: builderIO/qwik-city-e2e event-type: main-updated ############ Everything is fine ############ requirements-passed: name: All requirements are met runs-on: ubuntu-latest needs: - test-unit - test-e2e - test-cli-e2e - lint-package - build-docs - build-insights if: always() steps: - name: check status if: | !( (needs.test-unit.result == 'success' || needs.test-unit.result == 'skipped') && (needs.test-e2e.result == 'success' || needs.test-e2e.result == 'skipped') && (needs.test-cli-e2e.result == 'success' || needs.test-cli-e2e.result == 'skipped') && (needs.lint-package.result == 'success' || needs.lint-package.result == 'skipped') && (needs.build-docs.result == 'success' || needs.build-docs.result == 'skipped') && (needs.build-insights.result == 'success' || needs.build-insights.result == 'skipped') ) run: exit 1 ================================================ FILE: .github/workflows/closing-issues.yml ================================================ name: Closing Issues For Inactivity on: schedule: - cron: '0 0 * * *' jobs: close-issues: if: github.repository == 'QwikDev/qwik' runs-on: ubuntu-latest steps: - name: needs reproduction uses: actions-cool/issues-helper@v3 with: actions: 'close-issues' token: ${{ secrets.GITHUB_TOKEN }} labels: 'STATUS-2: needs reproduction' inactive-day: 14 - name: missing info uses: actions-cool/issues-helper@v3 with: actions: 'close-issues' token: ${{ secrets.GITHUB_TOKEN }} labels: 'STATUS-2: missing info' inactive-day: 14 ================================================ FILE: .github/workflows/deploy-docs.yml ================================================ # a workflow that runs after the "Qwik CI" workflow is successful # and deploys the documentation to CloudFlare Pages. name: Deploy Docs on: workflow_run: workflows: ['Qwik CI'] types: - completed permissions: actions: read deployments: write contents: read pull-requests: write jobs: deploy: name: Cloudflare Pages Deployment if: > github.repository == 'QwikDev/qwik' runs-on: ubuntu-latest steps: - name: Check for docs artifact id: check-artifact uses: actions/github-script@v7 with: retries: 3 script: | try { const artifacts = await github.rest.actions.listWorkflowRunArtifacts({ owner: context.repo.owner, repo: context.repo.repo, run_id: context.payload.workflow_run.id }); const hasDocsArtifact = artifacts.data.artifacts.some(a => a.name === 'artifact-docs'); core.setOutput('has-docs', hasDocsArtifact); } catch (error) { console.error('Error checking for artifacts:', error); core.setOutput('has-docs', false); } - name: Checkout code if: ${{ steps.check-artifact.outputs.has-docs == 'true' }} uses: actions/checkout@v5 - name: Download docs artifact if: ${{ steps.check-artifact.outputs.has-docs == 'true' }} uses: actions/download-artifact@v4 with: name: artifact-docs github-token: ${{ secrets.GITHUB_TOKEN }} run-id: ${{ github.event.workflow_run.id }} path: packages/docs - name: Verify dist directory exists if: ${{ steps.check-artifact.outputs.has-docs == 'true' }} run: | ls -la packages/docs if [ ! -d "packages/docs/dist" ]; then echo "Creating dist directory" mkdir -p packages/docs/dist cp -r packages/docs/* packages/docs/dist/ || true fi # not the official version, so be careful when updating - name: Deploy to Cloudflare Pages if: ${{ steps.check-artifact.outputs.has-docs == 'true' }} uses: AdrianGonz97/refined-cf-pages-action@6c0d47ff7c97c48fa702b6d9f71f7e3a7c30c7d8 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} projectName: 'qwik-docs' directory: packages/docs/dist githubToken: ${{ secrets.GITHUB_TOKEN }} - name: Skip message when no docs artifact if: ${{ steps.check-artifact.outputs.has-docs != 'true' }} run: echo "No docs artifact found, skipping deployment" ================================================ FILE: .github/workflows/labeling-issues.yml ================================================ name: Labling Issues on: issues: types: [labeled] jobs: handle-labeled: if: github.repository == 'QwikDev/qwik' runs-on: ubuntu-latest steps: - name: ensure STATUS-1 label is present id: status-1-label-presence # GH's built-in functions do not allow to search for array values that start with something, so we're using node for this run: | echo present=$( node -e ' const labels = JSON.parse(`${{ toJSON(github.event.issue.labels.*.name) }}`); console.log(labels.some(l => l.startsWith("STATUS-1:"))); ' ) >> $GITHUB_OUTPUT - name: remove needs triage if: steps.status-1-label-presence.outputs.present == 'true' && (contains(github.event.label.name, 'STATUS-2:') || contains(github.event.label.name, 'STATUS-3:')) uses: actions-cool/issues-helper@v3 with: actions: 'remove-labels' token: ${{ secrets.GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} labels: 'STATUS-1: needs triage' - name: needs reproduction time limit if: contains(github.event.label.name, 'needs reproduction') uses: actions-cool/issues-helper@v3 with: actions: 'create-comment' token: ${{ secrets.GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} body: | Hello @${{ github.event.issue.user.login }}. Please provide a [minimal reproduction](https://stackoverflow.com/help/minimal-reproducible-example) using a GitHub repository or [StackBlitz](https://qwik.new). [Here](https://antfu.me/posts/why-reproductions-are-required#why-reproduction) is why we really need a minimal reproduction. Issues marked with `needs reproduction` will be automatically closed if they have no activity within 14 days. Thanks 🙏 - name: missing info time limit if: contains(github.event.label.name, 'missing info') uses: actions-cool/issues-helper@v3 with: actions: 'create-comment' token: ${{ secrets.GITHUB_TOKEN }} issue-number: ${{ github.event.issue.number }} body: | Hello @${{ github.event.issue.user.login }}. Please provide the missing information requested above. Issues marked with `missing info` will be automatically closed if they have no activity within 14 days. Thanks 🙏 ================================================ FILE: .gitignore ================================================ # Keep "OS" and "IDE and local environment" ignores on your local machine in user home # git config --global core.excludesFile ~/.gitignore # https://git-scm.com/docs/gitignore # OS **/.DS_Store etc temp .history .lh *. **/*.log *.node # Application qwik-app/ /server/ /starters/**/server/ /packages/*/server/ !/packages/qwik/server/ /packages/*/src/styled-system/ todo-express/ target !/packages/docs/src/routes/demo/events/target src/napi/package-* # Node node_modules # Artifacts tsc-out dist dist-dev external lib tsdoc-metadata.json packages/qwik/bindings # IDE and local environment .idea .eslintcache test-results .direnv # Package Managers .yarn/* !.yarn/releases .pnpm-store/* # Local Netlify folder .netlify sandbox # AI tools .planning # We need to ignore this because "changesets" will try to replace it /CHANGELOG.md ================================================ FILE: .node-version ================================================ 24 ================================================ FILE: .nvmrc ================================================ 24 ================================================ FILE: .prettierignore ================================================ **/**.api.md **/*.log **/.DS_Store *. pnpm-lock.yaml .* !.eslintrc.cjs !.prettierignore !.prettierrc.json # Build output dist dist-dev lib target starters/apps/**/dist node_modules tsconfig.tsbuildinfo # REPL files packages/docs/public/repl/repl-sw.js* # build output packages/*/lib packages/*/dist packages/*/server # API output files packages/docs/src/routes/api # Prettier doesn't handle mdx files well packages/docs/**/*.mdx packages/insights/drizzle packages/insights/.netlify packages/insights/scripts packages/insights/**/*.gen.d.ts packages/qwik-labs/lib-types packages/qwik-labs/vite # insights cache files **/q-insights.json # Exclude builder js files from formatting - delete after migration packages/docs/public/builder ================================================ FILE: .prettierrc.json ================================================ { "plugins": ["./node_modules/prettier-plugin-jsdoc/dist/index.js"], "jsdocPreferCodeFences": true, "tsdoc": true, "trailingComma": "es5", "tabWidth": 2, "semi": true, "singleQuote": true, "printWidth": 100, "useTabs": false } ================================================ FILE: .vscode/extensions.json ================================================ { "recommendations": [ "dbaeumer.vscode-eslint", "unifiedjs.vscode-mdx", "esbenp.prettier-vscode", "ms-playwright.playwright", "rust-lang.rust-analyzer", "ms-azuretools.vscode-docker", "manucorporat.vermoji", "vadimcn.vscode-lldb", "streetsidesoftware.code-spell-checker", "vitest.explorer" ], "unwantedRecommendations": [] } ================================================ FILE: .vscode/launch.json ================================================ { // Use IntelliSense to learn about possible attributes. // Hover to view descriptions of existing attributes. // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 "version": "0.2.0", "configurations": [ { "type": "node", "name": "docs dev.debug", "request": "launch", "skipFiles": ["/**"], "cwd": "${workspaceFolder}/packages/docs", "program": "${workspaceFolder}/packages/docs/node_modules/vite/bin/vite.js", "args": ["--mode", "ssr", "--force"] }, { "type": "node", "name": "insights dev.debug", "request": "launch", "skipFiles": ["/**"], "cwd": "${workspaceFolder}/packages/insights", "program": "${workspaceFolder}/packages/insights/node_modules/vite/bin/vite.js", "args": ["--mode", "ssr", "--force"] }, { "type": "node", "name": "docs build.client", "request": "launch", "skipFiles": ["/**"], "cwd": "${workspaceFolder}/packages/docs", "program": "${workspaceFolder}/packages/docs/node_modules/vite/bin/vite.js", "args": ["build"] }, { "type": "node", "name": "docs build.server", "request": "launch", "skipFiles": ["/**"], "cwd": "${workspaceFolder}/packages/docs", "program": "${workspaceFolder}/packages/docs/node_modules/vite/bin/vite.js", "args": ["build", "-c", "adapters/cloudflare-pages/vite.config.mts"] }, { "type": "node", "name": "preloader-test build.client", "request": "launch", "runtimeExecutable": "pnpm", "runtimeArgs": [ "run", "build.client" ], "skipFiles": ["/**"], "cwd": "${workspaceFolder}/starters/apps/preloader-test" }, { "type": "node", "name": "e2e.test", "request": "launch", "console": "integratedTerminal", "internalConsoleOptions": "neverOpen", "program": "${workspaceFolder}/./node_modules/tsm/bin.js", "cwd": "${workspaceFolder}", "args": ["./starters/dev-server.ts", "3301"] }, { "type": "node", "name": "vitest", "request": "launch", "console": "integratedTerminal", "internalConsoleOptions": "neverOpen", "program": "${workspaceFolder}/./node_modules/vitest/vitest.mjs", "cwd": "${workspaceFolder}", "args": ["${file}"] } ] } ================================================ FILE: .vscode/qwik.code-snippets ================================================ { "Qwik component": { "scope": "typescriptreact", "prefix": "q:component w/props", "description": "Qwik component w/ props", "body": [ "export interface ${1:${TM_FILENAME_BASE/(.*)/${1:/capitalize}/}}Props {", " $2", "}", "", "export const $1 = component$((props: $1Props) => {", " const state = useStore({", " $3", " });", " ", " return <${4:button} on${5:Click}$={(${6:e}) => {$7}}>$8", "});", ], }, "Qwik component (simple)": { "scope": "javascriptreact,typescriptreact", "prefix": "q:component simple", "description": "Simple Qwik component", "body": [ "export const ${1:${TM_FILENAME_BASE/(.*)/${1:/capitalize}/}} = component$(() => {", " return <${2:button}>$4", "});", ], }, "Qwik state": { "scope": "javascriptreact,typescriptreact", "prefix": "q:useStore$", "description": "useStore() declaration", "body": ["const ${1:state} = useStore({", " $2", "});", "$0"], }, "Qwik signal": { "scope": "javascriptreact,typescriptreact", "prefix": "q:useSignal", "description": "useSignal() declaration", "body": ["const ${1:signal} = useSignal($2);", "$0"], }, "$ hook": { "scope": "javascriptreact,typescriptreact", "prefix": "q:$", "description": "$() function hook", "body": ["$(() => {", " $0", "});", ""], }, "useVisibleTask": { "scope": "javascriptreact,typescriptreact", "prefix": "q:useVisibleTask", "description": "useVisibleTask$() function hook", "body": ["useVisibleTask$(({ track }) => {", " $0", "});", ""], }, "useTask": { "scope": "javascriptreact,typescriptreact", "prefix": "q:useTask", "description": "useTask$() function hook", "body": ["useTask$(({ track }) => {", " track(() => $1);", " $0", "});", ""], }, "useResource": { "scope": "javascriptreact,typescriptreact", "prefix": "q:useResource$", "description": "useResource$() declaration", "body": ["const $1 = useResource$(({ track, previous, cleanup }) => {", " $0", "});", ""], }, "useOn": { "scope": "javascriptreact,typescriptreact", "prefix": "q:useOn", "description": "useOn declaration", "body": ["useOn(", "'$1',", "$((event) => {", " const { $3 } = event as $2;", " })", ");"], }, "useOnDocument": { "scope": "javascriptreact,typescriptreact", "prefix": "q:useOnDocument", "description": "useOnDocument declaration", "body": [ "useOnDocument(", "'$1',", "$((event) => {", " const { $3 } = event as $2;", " })", ");", ], }, "useOnWindow": { "scope": "javascriptreact,typescriptreact", "prefix": "q:useOnWindow", "description": "useOnWindow declaration", "body": [ "useOnWindow(", "'$1',", "$((event) => {", " const { $3 } = event as $2;", " })", ");", ], }, } ================================================ FILE: .vscode/settings.json ================================================ { "vitest.include": ["**/*.unit.{js,mjs,cjs,ts,mts,cts,jsx,tsx}"], "vitest.exclude": [ "**/node_modules/**", "**/dist/**", "**/dist-dev/**", "**/cypress/**", "**/.{idea,git,cache,output,temp}/**" ], "javascript.preferences.autoImportFileExcludePatterns": ["node:test"], "typescript.preferences.preferTypeOnlyAutoImports": true, "typescript.tsdk": "./node_modules/typescript/lib", "typescript.enablePromptUseWorkspaceTsdk": true } ================================================ FILE: @types/bun.d.ts ================================================ declare const Bun: { fileURLToPath: (url: string) => string; env: any; file: (path: string) => { text: () => Promise; stream: () => Promise>; }; }; ================================================ FILE: @types/deno.d.ts ================================================ declare module 'https://deno.land/std/path/mod.ts' { export function extname(paths: string): string; export function fromFileUrl(url: string): string; export function join(...paths: string[]): string; } interface FsFile { readable: ReadableStream; } declare const Deno: { env: any; open(path: string, mode: { read: boolean }): Promise; readTextFile(path: string): Promise; readFile(path: string): Promise; version: { deno: string; }; }; ================================================ FILE: AGENTS.md ================================================ # Qwik — AI Agent Instructions > Canonical instruction file for AI coding agents working on the Qwik monorepo. > For detailed contributor setup, see [CONTRIBUTING.md](./CONTRIBUTING.md). ## Overview Qwik is a **resumable** web framework — it serializes application state and framework state into HTML during SSR, then resumes on the client without re-executing component code. This enables it to stream javascript (a.k.a javascript streaming). There’s no waiting for the entire code to be downloaded (a.k.a hydration). The developer can write code very similar to other reactive frameworks; the app is automatically instant, regardless the amount of javascript. **Key concepts:** Resumability, QRLs (lazy-loading primitives), the `$` suffix transform, fine-grained signals, and the Rust-based optimizer. ## Monorepo Layout | Package | Path | Description | | ------------------------- | ----------------------------- | ---------------------------------------------- | | `@builder.io/qwik` | `packages/qwik` | Core framework (runtime + optimizer) | | `@builder.io/qwik-city` | `packages/qwik-city` | Meta-framework (routing, middleware, adapters) | | `@builder.io/qwik-react` | `packages/qwik-react` | React integration layer | | `@builder.io/qwik-auth` | `packages/qwik-auth` | Auth.js integration | | `@builder.io/qwik-dom` | `packages/qwik-dom` | Server-side DOM implementation | | `@builder.io/qwik-worker` | `packages/qwik-worker` | Web Worker support (experimental) | | `@builder.io/qwik-labs` | `packages/qwik-labs` | Experimental features (private) | | `eslint-plugin-qwik` | `packages/eslint-plugin-qwik` | ESLint rules for Qwik | | `create-qwik` | `packages/create-qwik` | Project scaffolding CLI | | `qwik-docs` | `packages/docs` | Documentation site (private) | | `insights` | `packages/insights` | Analytics dashboard (private) | ## Setup **Requirements:** Node ≥22.18.0, pnpm ≥10.14.0 ```bash pnpm install pnpm build.local # builds everything without Rust (copies optimizer from npm) ``` Use `pnpm build.full` only if you modified Rust/optimizer code. Prefer `pnpm build --qwik --qwikcity --dev` to build qwik and qwik-city faster. ## Key Commands | Task | Command | Notes | | ------------------------ | ------------------------ | ------------------------------------------- | | **Install** | `pnpm install` | | | **Install** | `pnpm install` | | | **Build (no Rust)** | `pnpm build.local` | For a fresh start | | **Build (with Rust)** | `pnpm build.full` | Only for optimizer changes | | **Build core only** | `pnpm build.core` | Fast — just Qwik + Qwik City + types | | **Watch mode** | `pnpm build.watch` | Rebuilds on change | | **Unit tests** | `pnpm test.unit` | Vitest — runs `packages/**/*.unit.{ts,tsx}` | | **E2E tests (Chromium)** | `pnpm test.e2e.chromium` | Playwright | | **E2E tests (City)** | `pnpm test.e2e.city` | Qwik City–specific E2E | | **Lint** | `pnpm lint` | ESLint + Prettier + Rust lint | | **Lint fix** | `pnpm lint.fix` | Auto-fix ESLint issues | | **Format** | `pnpm fmt` | Prettier + syncpack | | **Type check** | `pnpm tsc.check` | Full TypeScript check | | **Update API docs** | `pnpm api.update` | Regenerates public API `.md` files | | **Create changeset** | `pnpm change` | Interactive — creates `.changeset/*.md` | | **Dev server** | `pnpm serve` | Port 3300 | | **Docs dev** | `pnpm docs.dev` | Documentation site | ### Running a Single Test File ```bash # Unit test — single file pnpm vitest run packages/qwik/src/core/qrl/qrl.unit.ts # E2E test — single file pnpm playwright test starters/e2e/e2e.events.spec.ts --project chromium ``` ## Architecture Essentials ### Resumability Qwik serializes the full application state into HTML at SSR time. On the client, it **resumes** from that serialized state instead of re-executing components (no hydration). The serialization/deserialization logic lives in `packages/qwik/src/core/container/`. ### QRL & the `$` Transform A **QRL** (Qwik Resource Locator) is a lazy reference to a closure. Any function ending with `$` (e.g., `component$`, `useTask$`, `$()`) creates a QRL boundary — the optimizer extracts these into separate chunks for lazy loading. - QRL implementation: `packages/qwik/src/core/qrl/` - The Rust optimizer rewrites `$`-suffixed calls at build time ### Signals Fine-grained reactivity system. Signals track subscriptions and update only the DOM nodes or tasks that read them — no virtual DOM diffing. - Implementation: `packages/qwik/src/core/state/signal.ts` - Stores (proxy-based deep reactivity): `packages/qwik/src/core/state/store.ts` ### Optimizer (Rust) The optimizer is a Rust-based compiler plugin (SWC transform) that: 1. Extracts `$`-suffixed closures into separate entry points 2. Captures lexical scope for serialization 3. Generates manifest metadata for prefetching - Rust source: `packages/qwik/src/optimizer/core/` - WASM build: `packages/qwik/src/wasm/` - Native bindings: `packages/qwik/src/napi/` ### Qwik City (Meta-framework) Qwik City provides file-based routing, data loaders (`routeLoader$`), actions (`routeAction$`), middleware, and server adapters. - Runtime: `packages/qwik-city/src/runtime/` - Build tooling: `packages/qwik-city/src/buildtime/` - Adapters: `packages/qwik-city/src/adapters/` ## Code Style **Config:** Prettier (`.prettierrc.json`) + ESLint 9 flat config (`eslint.config.js`) | Rule | Setting | | -------------- | -------------------------- | | Semi | `true` | | Quotes | Single | | Print width | 100 | | Tabs | Spaces (2) | | Trailing comma | ES5 | | `no-console` | Error (warn/error allowed) | | `curly` | Always required | ### Naming Conventions | Pattern | Usage | Example | | -------------- | ------------------------------------------------- | ----------------------------------- | | `use*` | Hooks (must be called in component or task scope) | `useSignal`, `useStore`, `useTask$` | | `*$` | QRL boundary — optimizer extracts the closure | `component$`, `routeLoader$` | | `create*` | Factory functions | `createDOM`, `createContextId` | | `*.unit.ts(x)` | Unit test files | `qrl.unit.ts` | | `*.spec.ts` | E2E test files | `e2e.events.spec.ts` | ## Testing ### Unit Tests (Vitest) - File pattern: `*.unit.ts` / `*.unit.tsx` - Config: `vitest.config.ts` (root) - Run all: `pnpm test.unit` - Run one: `pnpm vitest run ` - Server-side DOM helper: `createDOM()` from `@builder.io/qwik/testing` ### E2E Tests (Playwright) - File pattern: `*.spec.ts` in `starters/e2e/` - Config: `starters/playwright.config.ts` - Run: `pnpm test.e2e.chromium` - Run one: `pnpm playwright test --project chromium` - Additional E2E suites: `e2e/adapters-e2e/`, `e2e/docs-e2e/`, `e2e/qwik-react-e2e/` ### Rust Tests - Run: `pnpm test.rust` (or `make test`) - Update snapshots: `pnpm test.rust.update` (or `make test-update`) ## Git Workflow ### Commit Convention ``` type(scope): description ``` Types: `feat`, `fix`, `docs`, `lint`, `refactor`, `perf`, `test`, `chore` - Use imperative mood ("add feature" not "added feature") - No trailing period - Scope is optional but encouraged (e.g., `fix(qwik-city): ...`) ### Changesets If your change affects published packages, create a changeset: ```bash pnpm change ``` This creates a `.changeset/*.md` file describing the change. The core packages (`@builder.io/qwik`, `@builder.io/qwik-city`, `eslint-plugin-qwik`, `create-qwik`) are **fixed-versioned** — they always release together. ### Branch Strategy - **Base branch:** `main` (trunk-based development) - PRs target `main` - CI runs on all PRs ### Before Pushing a PR 1. `pnpm build.core` 2. `pnpm test.unit` (run relevant tests) 3. `pnpm lint` 4. `pnpm api.update` (if you changed public API) 5. `pnpm change` (to document patches or new features) ## Boundaries — What NOT to Do 1. **Don't run the full test suite** — Use `pnpm test.unit` or target specific files. The full `pnpm test` runs build + all tests and takes a very long time. 2. **Don't forget `pnpm api.update`** — If you change any public API, CI will fail without regenerated API docs. 3. **Don't modify Rust code without rebuilding** — After touching `packages/qwik/src/optimizer/core/`, run `pnpm build.full` (requires Rust toolchain + wasm-pack). 4. **Don't skip changesets for user-facing changes** — CI checks for changesets on PRs that touch published packages. 5. **Don't commit `.only` tests** — ESLint rule `no-only-tests` blocks this. 6. **Don't edit generated files** — Files in `dist/`, `lib/`, and API docs under `packages/docs/` are generated. Edit the source instead. ================================================ FILE: CLAUDE.md ================================================ @AGENTS.md ================================================ FILE: CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: - Demonstrating empathy and kindness toward other people - Being respectful of differing opinions, viewpoints, and experiences - Giving and gracefully accepting constructive feedback - Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience - Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: - The use of sexualized language or imagery, and sexual attention or advances of any kind - Trolling, insulting or derogatory comments, and personal or political attacks - Public or private harassment - Publishing others' private information, such as a physical or email address, without their explicit permission - Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at info@builder.io. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. ================================================ FILE: CONTINUOUS_BUILD.md ================================================ # Continuous Build Artifacts This repo contains build artifacts that are generated as part of the continues build pipeline. Currently supported artifacts: - [`@builder.io/qwik`](https://github.com/QwikDev/qwik-build) - [`@builder.io/qwik-city`](https://github.com/QwikDev/qwik-city-build) - [`@builder.io/qwik-labs`](https://github.com/QwikDev/qwik-labs-build) The build artifact is created if: - Code is merged to `main` branch - Code is merged to `build/*` branch ## How to use The build artifacts are useful if you want to: - Install an un-released change. - Bisect which specific commit caused a regression. ## Install specific build artifact To install a specific build artifact change you `package.json` like so (not all lines may be needed): ```json { "dependencies": { "@builder.io/qwik": "github:QwikDev/qwik-build#SHA", "@builder.io/qwik-city": "github:QwikDev/qwik-city-build#SHA", "@builder.io/qwik-labs": "github:QwikDev/qwik-labs-build#SHA" } } ``` Where `#SHA` is one of the following: - `#SHA` - Install a specific build SHA. You can get the SHA from: - [`@builder.io/qwik`](https://github.com/QwikDev/qwik-build/commits/) commits - [`@builder.io/qwik-city`](https://github.com/QwikDev/qwik-city-build/commits/) commits - [`@builder.io/qwik-labs`](https://github.com/QwikDev/qwik-labs-build/commits/) commits - `#build/name` (or `#main`) - Install a specific `build/*` (or `#main`) branch: - [`@builder.io/qwik`](https://github.com/QwikDev/qwik-build/branches/) branches - [`@builder.io/qwik-city`](https://github.com/QwikDev/qwik-city-build/branches/) branches - [`@builder.io/qwik-labs`](https://github.com/QwikDev/qwik-labs-build/branches/) branches > NOTE: Package managers will treat any SHA in the lock file which is on the branch as valid, and so they will not auto upgrade to the latest. For this reason this is not recommended. ## Bisect for regression You can bisect different commits to `main` to determine which specific change has cause the regression. 1. Install latest to get an upper mound 2. Install oldest known good to get a lower bound 3. Keep bisecting until you find a specific SHA where the code breaks. When creating the issue please include which SHA has caused the regression. ================================================ FILE: CONTRIBUTING.md ================================================ # Contributing to Qwik Thank you for taking an interest in contributing to Qwik! We appreciate you! 🫶🏽 Below are the guidelines on how to help in the best possible way. ## Submitting an Issue Before creating a new issue, please search through open issues using the [GitHub issue search bar](https://docs.github.com/en/issues/tracking-your-work-with-issues/filtering-and-searching-issues-and-pull-requests). You might find the solution to your problem, or can verify that it is an already known issue. We want a bug-free and best-performing project. That's why we take all reported issues to heart. But please be aware that if we can't reproduce the problem, we won't have a way of locating and adequately fixing it. Therefore, to solve the problem in the best possible way, please create a minimal repository that reproduces the problem with the least possible code explaining and demonstrating the error. Without enough information to reproduce the issue, we will close it because we can't recreate and solve it. ## Triaging Issues If you're interested in helping out with triaging issues, please follow the [Triaging Guide](./contributing/TRIAGE.md). ## Submitting a Pull Request (PR) ### Branch Organization We adopt [trunk-based development](https://trunkbaseddevelopment.com/) therefore all Pull Requests are made against the main branch. Before releasing, we merge `main` into a release branch, for testing purposes. ### Good first issue The issues marked with [_Good first issue_](https://github.com/QwikDev/qwik/issues?q=is%3Aissue+is%3Aopen+label%3A%22COMMUNITY%3A++good+first+issue%22) are a good starting point to familiarize yourself with the project. Before solving the problem, please check with the maintainers that the issue is still relevant. Feel free to leave a comment on the issue to show your intention to work on it and prevent other people from unintentionally duplicating your effort. ### Sending a Pull Request Before submitting a pull request, consider the following guidelines: - Fork the repository into your own account. - In your forked repository, create a new branch: `git checkout -b my-branch main` - Make your changes/fixes. - Run `pnpm fmt` to lint the code. - Add a changeset with `pnpm change` if needed ([follow this tutorial](https://go.screenpal.com/watch/cZivIcVPJQV)) - Push your branch to GitHub: `git push origin my-branch` - In GitHub, send a pull request to `QwikDev:main`. > If you aren't sure your PR is ready, open it as a [draft](https://github.blog/2019-02-14-introducing-draft-pull-requests/) to make it clear to the maintainer. ### ⚠ Troubleshooting PR build issues on CI Every PR is being automatically merged with `main` before the CI Github actions run. That's why if the CI checks aren't passing your PR branch is probably not up to date. **For non documentation PRs please do the following:** 1. Merge `main` into your PR branch 2. Run `pnpm api.update` 3. Run `pnpm build.local` or `pnpm build.full` if you made a change to the Rust code 4. Commit and push any changes as a result of the above steps ## Local development This is the best approach because all required dependencies will be installed in the docker container for you and won't affect your personal configuration in any way. ### Prerequisites You need to have these tools up and running in your local machine: - an editor. We recommend [VSCode](https://code.visualstudio.com/). - one of the following: - [Nix](https://nixos.org) - [Docker](https://www.docker.com/) - Locally installed NodeJS v22+ and optionally Rust #### Nix [Nix](https://nixos.org/download.html) can be used on macOS and Linux. It keeps installation files in `/nix` and doesn't write anywhere else. It has a declarative configuration in the `flake.nix` file, which describes all the tools needed to build the project. - Install it on your machine and enable flakes. The [DetSys installer](https://github.com/DeterminateSystems/nix-installer) makes that easy. - run `nix develop` in the project root to open a shell with all the tools, or use `direnv` to have them automatically added into your current shell. ##### Nix + Direnv (optional) You can additionally use [direnv](https://direnv.net/) to automatically load the dev environment when you enter the project directory. There is also a VSCode plugin for direnv that reloads the extensions so they get environment changes. When you install direnv, you'll need to allow it once with `direnv allow` in the project root. From then on, when you `cd` into the project, it will automatically have the correct tools installed. #### Docker - Install the [Dev Containers](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) extension in your VSCode. - Once installed you will be prompted to 'Reopen the folder to develop in a container [learn more](https://code.visualstudio.com/docs/devcontainers/containers) or Clone repository in Docker volume for [better I/O performance](https://code.visualstudio.com/docs/devcontainers/containers#_quick-start-open-a-git-repository-or-github-pr-in-an-isolated-container-volume)'. If you're not prompted, you can run the `Dev Containers: Open Folder in Container` command from the [VSCode Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette). Alternatively you can use [devcontainers/cli](https://github.com/devcontainers/cli): - Install devcontainers following their documentation. - In your terminal navigate to the Qwik's project root directory. - Then run `devcontainer up --workspace-folder .`. This command will start a Docker container with all required environment dependencies. > [!TIP] > If you are using Podman, be sure to update the [VSCode dev container settings](https://code.visualstudio.com/remote/advancedcontainers/docker-options#_podman). Don't forget to allocate enough resources to the Podman machine to avoid slow builds. > [!NOTE] > You may run into an `EEXISTS` error when the Dev Container runs the "updateContentCommand" script. This may happen if pnpm gets installed automatically during the setup process. You can ignore the error because the container will be setup correctly, then run `pnpm install` in the project root once the container is connected and the terminal is available. > [!CAUTION] > The Dev Container may not work on Windows properly due to a difference with Windows container host volume permissions and ownership. It's recommended to use Mac or Linux instead, or configure your environment to build the project without Dev Containers. ##### Using development container without Dev Containers and VSCode If you would like to make use of the development container solution, but don't use VSCode or Dev Containers, you still can do so, by following steps: - Build development container locally: `cd .devcontainer; docker build -t qwik-container .` - Run development container from Qwik project root, binding the directory to container: `cd ..; docker run --rm -d --name qwik-container -p 3300:3300 -p 9229:9299 -v $PWD:/home/circleci/project -t qwik-container` Docker command does: - Create a new container that is removed once stopped, - In daemon mode, - With name `qwik-container`, - That exposes the ports `3300` and `9229`, and - Binds `qwik` project directory to container working directory. ##### Podman extras > This section is highly influenced by SO answer: https://serverfault.com/a/1075838/352338 > If you use [Podman](https://podman.io/) instead of Docker as your containers engine, then you need to know the following: - Container runs as user `circleci` with UID `1001` and GID `1002`. - As you are accustomed to using Podman, you will need to append `:Z` to `volumes | -v` parameter so the command becomes: ```bash $ subuid_size=65536 $ subgid_size=65536 $ container_uid=1001 $ container_gid=1002 $ podman run --rm \ --user $container_uid:$container_gid \ --uidmap=0:1:$container_uid \ --uidmap=$((container_uid + 1)):$((container_uid + 1)):$((subuid_size - $container_uid)) \ --uidmap=$container_uid:0:1 \ --gidmap=0:1:$container_gid \ --gidmap=$((container_gid + 1)):$((container_gid + 1)):$((subgid_size - $container_gid)) \ --gidmap=$container_gid:0:1 \ -d --name qwik-container \ -p 3300:3300 -p 9229:9299 \ -v .:/home/circleci/project:Z \ -t qwik-container ``` #### Locally installed tools If you're not able to use the dev container, make sure you have NodeJS v18+ installed, as well as `pnpm`. Furthermore, to build the optimizer you optionally need Rust. 1. Make sure [Rust](https://www.rust-lang.org/tools/install) is installed. 2. Install [wasm-pack](https://rustwasm.github.io/wasm-pack/installer/) with `cargo install wasm-pack` . 3. Node version >= `22`. 4. Make sure you have [pnpm](https://pnpm.io/installation) installed. 5. run `pnpm install` > On Windows, Rust requires [C++ build tools](https://visualstudio.microsoft.com/visual-cpp-build-tools/). You can also select _Desktop development with C++_ > while installing Visual Studio. --- ## Development To build Qwik for local development, install the dev dependencies using [pnpm](https://pnpm.io/) and then do an initial build. ```shell pnpm install && pnpm build.local ``` If you want to work on the Rust code, use `build.full` instead of `build.local`. > [!NOTE] > After running `build.local`, you may see Git diffs for API-related files and `JSXNode`. You should run the `api.update` script to resolve them. ### Fast build This will build only Qwik and Qwik City and their types. This is not enough to run the docs. ```shell pnpm build.core ``` ### Custom build Once you have done a full build, the types are built, and you can build just the code you're working on. For qwik and qwik-city, you can do very fast rebuilds with ```shell pnpm build --dev --qwik --qwikcity ``` The `--dev` flag skips type checking and generating. You can run `pnpm build` without parameters to see which flags are available. Notable: - `--tsc`: build types - `--api`: build API docs and type bundles. Requires `--tsc` to have run. - `--build`: Qwik (you'll probably also need `--dev`) - `--qwikcity`: Qwik City (you'll probably also need `--dev`) - `--qwikreact`: Qwik React - `--qwiklabs`: Qwik Labs - `--eslint`: Eslint plugin E.g. to build only the React integration, you'd run `pnpm build --qwikreact`. ### Full build without Rust This builds everything except Rust prerequisites and the optimizer binaries. Instead, those binaries are copied from the latest Qwik package on NPM. ```shell pnpm build.local ``` ### Full build with Rust It will build **everything**, including Rust packages and WASM. > First build might be very slow. - Builds each submodule - Generates bundled `.d.ts` files for each submodule with [API Extractor](https://api-extractor.com/) - Checks the public API hasn't changed - Builds a minified `core.min.mjs` file - Generates the publishing `package.json` ```shell pnpm build.full ``` The build output will be written to `packages/qwik/dist`, which will be the directory that is published to [@builder.io/qwik](https://www.npmjs.com/package/@builder.io/qwik). To update the Rust test snapshots after you've made changes to the Rust code, run `pnpm test.rust.update`. ### Run in your own app Say you made changes to the repo and you want to try them out in your app. Once built, all the Qwik packages are directly usable in your project by using the linking in your package manager. This is very easy to do with `pnpm`: Assuming qwik is in `../qwik`, run this inside the root of your app: ```shell pnpm link ../qwik/packages/qwik pnpm link ../qwik/packages/qwik-city ``` Other package managers probably need to first be told about the packages. For example, with `bun` you need to `cd ../qwik/packages/qwik` and `bun link`, repeat for `qwik-city`. Then in your app run `bun link @builder.io/qwik @builder.io/qwik-city`. If you can't use package linking, just copy the contents of `packages/qwik` into your projects' `node_modules/@builder.io/qwik` folder, and/or the contents of `packages/qwik-city` into your projects' `node_modules/@builder.io/qwik-city` folder. ### Working on the docs site At the root of the Qwik repo folder run: ```shell pnpm docs.dev ``` ### To open the test apps for debugging run ```shell pnpm serve ``` ### Unit Tests Only Unit tests use [vitest](https://vitest.dev) ```shell pnpm test.unit ``` ### E2E Tests Only E2E tests use [Playwright](https://playwright.dev/). To run the Playwright tests headless, from start to finish, run: ```shell pnpm test.e2e.chromium ``` Finally, you can use `pnpm --filter` command to run packages' commands, for example: ```shell pnpm --filter qwik-docs start ``` More commands can be found in each package's package.json scripts section. ### Updating dependencies To update all dependencies, run: ```shell pnpm deps ``` This will show an interactive UI to update all dependencies. Be careful about performing major updates, especially for the docs site, since not all functionality has test coverage there. Be sure to test thoroughly. ## Starter CLI `create-qwik` - [Starter CLI](https://github.com/QwikDev/qwik/blob/main/starters/README.md) ## Pull Requests - [Open Qwik in StackBlitz Codeflow](https://pr.new/github.com/QwikDev/qwik/) - Review PR in StackBlitz ![image](https://user-images.githubusercontent.com/4918140/195581745-8dfca1f9-2dcd-4f6a-b7aa-705f3627f8fa.png) ### Coding conventions Write code that is clean, simple and easy to understand. Complicated one-liners are generally frowned upon, unless they are for performance reasons and are clearly marked as such with a comment and explanation. When code does something unexpected, add a comment explaining why. When a comment is longer, prefer using `/** */` JSDoc comments as that will be auto-formatted as Markdown. JSDoc comments will also become part of the API documentation when they apply to exports, so write them as such. `pnpm fmt` is your friend, and we recommend setting up Prettier and using format-on-save in your editor. ### Commit conventions If you don't follow these commit conventions, your PR will be squashed. This means your local branch will not be part of the commit history of the target branch. For larger PRs, it would really help if you follow these guidelines. - Create a commit for each logical unit and make sure it passes linting. - Keep your commits focused and atomic. Each commit should represent a single, coherent change. - If you have commits like `wip lol` or `fixup`, squash them. Use `git rebase -i`. - Commits must follow the format: `type(scope): description` For example: `feat(qwik-city): confetti animations` or `chore: pnpm api.update` Common types include: - feat: A new feature - fix: A bug fix - docs: Documentation only changes - lint: Changes that do not affect the meaning of the code (white-space, formatting, etc) - refactor: A code change that neither fixes a bug nor adds a feature - perf: A code change that improves performance - test: Adding missing tests or correcting existing tests - chore: Changes to the build process or auxiliary tools and libraries such as documentation generation The `scope` is optional and should be a short identifier for the changed part of the code. - Use the imperative mood in the description. For example, use "add" instead of "added" or "adds". - For consistency, there should not be a period at the end of the commit message's summary line (the first line of the commit message). ### Writing good commit messages In addition to writing properly formatted commit messages, it's important to include relevant information so other developers can later understand _why_ a change was made. While this information usually can be found by digging into the code, pull request discussions or upstream changes, it may require a lot of work. - Be clear and concise in your commit messages. - Explain the reason for the change, not just what was changed. - If the commit fixes a specific issue, reference it in the commit message (e.g., "Fixes #123"). ### Adding a changeset Whenever you make a change that requires mentioning in the changelog, you should add a changeset. This will automatically generate meaningful release notes and changelog files. You can add multiple changesets in a PR, for example because you implement different features for different packages, or because you have multiple noteworthy commits. You create a new changeset file by running: ```shell pnpm change ``` This will ask you which packages should be included in the changeset, and if the changes require a new version bump. Generally you should not select `major`, and you should only select `minor` if there are new features or significant improvements. If you don't select either it will become `patch`. For your convenience, we prepared a video tutorial that covers the process of adding a changeset: [📽 TUTORIAL: Adding a changeset](https://go.screenpal.com/watch/cZivIcVPJQV) ## PR merging (maintainers) Make sure the PR follows all the guidelines in this document. Once you think the PR is good to merge, if the commits are "nice", you can merge the PR. If not, squash the PR. In case the PR is stuck waiting for the original author to apply a trivial change (a typo, capitalization change, etc.) and the author allowed the members to modify the PR, consider applying it yourself (or commit the existing review suggestion). You should pay extra attention to make sure the addition doesn't go against the idea of the original PR and would not be opposed by the author. ## Releasing (maintainers) Merge the "version" PR, that is automatically created when a PR with a changeset is merged. You can first edit the files it created to get a nicer changelog. Once CI passes, the GitHub Action will publish the new version to NPM. ================================================ FILE: Cargo.toml ================================================ [workspace] members = [ "packages/qwik/src/napi", "packages/qwik/src/wasm", "packages/qwik/src/optimizer/cli", "packages/qwik/src/optimizer/core", ] exclude = ["packages/qwik/src/wasm"] resolver = "2" [profile.release] debug = 0 lto = true codegen-units = 1 opt-level = "z" panic = "abort" ================================================ FILE: Dockerfile ================================================ FROM node:16.12.0-buster RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y ADD . / ENV PATH="/root/.cargo/bin:${PATH}" RUN make install-rust-deps RUN pnpm install RUN pnpm build ================================================ FILE: GOVERNANCE.md ================================================ # Qwik Project Governance This governance document reflects our dedication to maintaining Qwik as an open, fair, and collaborative project and is a continuation of our [community values](https://docs.google.com/document/d/1MrSp2caaREETHUL56C2fIIJeFJsBA_sWJ9raL6hWoo8/edit#heading=h.bpbzghkvfgrn). Qwik is rooted in a commitment to innovation and community-driven development where the needs of the community drive the framework's evolution. Our decisions are guided by what serves Qwik and the broader web ecosystem best, with a strong emphasis on seeking consensus. The following outlines the structure of the project, including the roles and responsibilities of its members. ## Community Contributors A Community contributor is any community member who contributes to the success of the framework. Contributors usually are part of one or more of the following categories: 1. **Code Contributors** - Developers who contribute by identifying issues, submitting pull requests, or maintaining community-driven Qwik projects. 2. **Docs Contributors** - Members who enhance or correct the Qwik documentation, ensuring it remains accurate and accessible. 3. **Support Contributors** - Members who assist other developers by answering questions and offering support. 4. **Content Creators** - Those who produce educational content, tutorials, and other resources to help the community better understand and use Qwik. 5. **Local Community Leaders** - Members who organize and lead local Qwik communities, fostering in-person engagement and knowledge sharing. ## Qwik Heroes Qwik Heroes are recognized as top contributors who have exceptional dedication and enthusiasm for Qwik. Heroes have easier access to the core team and participate in monthly meetings to provide feedback, ask questions, and discuss internal topics together with the team. #### Nomination Any community contributor can be nominated as a Qwik Hero by an existing member or by any of the leadership teams. Selections are made by the Community Management Team (and in conjunction with the core team for cases of “code heroes”). #### Status Change Removal of Qwik Heroes is done by either a voluntary resignation or by a Community Management Team decision, or (in extreme cases) by a Stewardship Team motion. Qwik Heroes who become inactive for 6 months are automatically reverted to regular community contributor status. ## Core Team Core team members are contributors who have merging rights to the project and are actively involved in the ongoing development of Qwik. They are essential to the framework's evolution, participating in weekly sprint meetings and Core Leadership meetings (although only Core Leadership members can vote in these meetings). The Core Team will have a Core Team Lead who will be in charge of the ongoing project management and development progress. #### Nomination A Qwik Hero member can be nominated as a Core Team member by any member of the Core Team. Nominations are decided upon by a standard Core Leadership motion. #### Status Change Removal of Core Team members is done by either a voluntary resignation or by a standard Core Leadership motion, or (in extreme cases) by a Stewardship Team motion. A Core Team member will be automatically converted back to a "Qwik Hero" if they are not active in the project for over 3 months. ## Core Leadership Team The Core Leadership Team includes Core Team members who are granted voting rights on strategic technical decisions. These individuals are selected because of their experience, judgment, good faith, and alignment with Qwik's core values. Members of this team are expected to participate in Core Leadership Team activities and meetings and can cast votes when consensus is not reached on a specific decision. #### Nomination Regular Core Team members can be nominated to the Core Leadership Team by any current Core Leadership member, with the final decision made through a standard Core Leadership motion. #### Status Change Removal of voting Core Leadership members is done by either a voluntary resignation or by a standard Core Leadership motion, or (in extreme cases) by a Stewardship Team motion. A Core Leadership member will be automatically converted to a regular Core Team member if they do not participate in 3 consecutive votes or have been inactive for over 4 months. ## Docs Team The Docs Team is responsible for maintaining and improving Qwik's documentation. This team ensures that the documentation is up-to-date, accurate, and user-friendly, and also handles the triage of docs-related issues and the merging of related PRs. #### Nomination A Qwik Hero member can be nominated as a Docs Team member by any member of the Docs Team. Nominations need to be approved by the Growth Manager. #### Status Change Removal of Docs Team members is done by either a voluntary resignation or by a Growth Manager decision, or (in extreme cases) by a Stewardship Team motion. A Docs Team member will be automatically converted back to a "Qwik Hero" if they are not active in the project for over 3 months. ## Community Management Team The Community Management Team oversees the onboarding, safety, and overall vibe of the Qwik community. They ensure that the community remains a friendly and inclusive space where members follow the Qwik community guidelines. The team is responsible for managing "Local Community Leaders" and "Support Heroes" and helping them succeed in their roles and contributions. #### Nomination Qwik Heroes may be nominated to the Community Management Team by any current team member. Nominations need to be approved by the Growth Manager. #### Status Change Removal of Community Management Team members is done by either a voluntary resignation or by a Growth Manager decision, or (in extreme cases) by a Stewardship Team motion. A Community Management Team member will be automatically converted back to a "Qwik Hero" if they are not active in the project for over 3 months. ## Outreach Team The Outreach Team is responsible of spreading Qwik's message, ensuring that more developers are introduced to the framework and give it a try. Their responsibilities include managing social media, collaborating with content creators, representing Qwik at conferences, and more. #### Nomination Qwik Heroes may be nominated to the Outreach Team by any current team member. Nominations need to be approved by the Growth Manager. #### Status Change Removal of Outreach Team members is done by either a voluntary resignation or by a Growth Manager decision, or (in extreme cases) by a Stewardship Team motion. An Outreach Team member will be automatically converted back to a "Qwik Hero" if they are not active in the project for over 3 months. ## Growth Manager The Growth Manager is responsible for overseeing the Community Management, Outreach, and Docs Teams, ensuring that their efforts are aligned and that messaging across these teams remains consistent. This role is crucial in driving the strategic direction of Qwik's growth and ensuring that all community-facing activities are cohesive and effective. The Growth Manager is appointed or replaced by a standard Stewardship Team motion. ## Stewardship Team The project's stewards are in charge of all aspects regarding the framework. This includes the development, community, and growth of the framework, but also creating proper management processes, managing sponsorships and budgets, collaborations, and more. The project stewards are: Misko Hevery and Shai Reznik. The project stewards will be used as "tiebreakers" in votes and hold veto rights on decisions (to protect the framework from rare and extreme cases). Because the framework can be forked by the community at any point, the project stewards must manage the project in a fair, honest, and thoughtful way, taking into account what's good for the community and resolving conflicting needs as much as possible. --- inspired by [Node](https://github.com/nodejs/node/blob/main/GOVERNANCE.md), [Vue](https://github.com/vuejs/vue/wiki/Governance-Document), [Astro](https://github.com/withastro/.github/blob/main/GOVERNANCE.md) and [Nuxt](https://github.com/nuxt/governance) ================================================ FILE: LICENSE ================================================ MIT License Copyright (c) 2024 QwikDev Copyright (c) 2021 BuilderIO Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: Makefile ================================================ install-rust: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y install-rust-deps: rustup update rustup target add wasm32-unknown-unknown cargo install cargo-insta rustup component add clippy add-target: rustup target add wasm32-unknown-unknown install-all: install-rust install-rust-deps install-cli: cd src/optimizer/cli && cargo install --path . fix: cargo fmt check: cargo fmt -- --check && cargo check --all-features lint: cargo clippy --all-features && cargo check --all-features && cargo fmt -- --check # We only test core because there are no other tests and qwik-napi breaks the build test: cargo test --manifest-path packages/qwik/src/optimizer/core/Cargo.toml test-update: if ! cargo test --manifest-path packages/qwik/src/optimizer/core/Cargo.toml; then \ cd packages/qwik/src/optimizer/core/src/snapshots/; \ for i in *.new; do f=$$(basename $$i .new); mv $$i $$f; done; \ cd -; \ cargo test --manifest-path packages/qwik/src/optimizer/core/Cargo.toml; \ fi publish-core: cd src/optimizer/core && cargo publish --all-features publish-cli: cd src/optimizer/cli && cargo publish publish: publish-core publish-cli validate: check lint test ================================================ FILE: README.md ================================================

Qwik Logo


Qwik CI



Instant-loading web apps, without effort

Qwik offers the fastest possible page load times - regardless of the complexity of your website. Qwik is so fast because it allows fully interactive sites to load with almost no JavaScript and [pickup from where the server left off](https://qwik.dev/docs/concepts/resumable/). As users interact with the site, only the necessary parts of the site load on-demand. This [precision lazy-loading](https://qwik.dev/docs/concepts/progressive/) is what makes Qwik so quick. ## Getting Started ```sh npm create qwik@latest # or pnpm create qwik@latest # or yarn create qwik@latest # or bun create qwik@latest ``` - Understand the difference between [resumable and replayable](https://qwik.dev/docs/concepts/resumable/) applications. - Learn about Qwik's high level [mental model](https://qwik.dev/docs/concepts/think-qwik/). ## Resources - [Docs](https://qwik.dev/) - [Examples](https://qwik.dev/examples/introduction/hello-world/) - [Tutorials](https://qwik.dev/tutorial/welcome/overview/) - [Videos](https://qwik.dev/media/#videos) - [Podcasts](https://qwik.dev/media/#podcasts) - [Presentations](https://qwik.dev/media/#presentations) - [Blogs](https://qwik.dev/media/#blogs) ## Community - Ping us at [@QwikDev](https://twitter.com/QwikDev) - Join our [Discord](https://qwik.dev/chat) community - Join all the [other community groups](https://qwik.dev/ecosystem/#community) ## Development - See [Contributing.md](https://github.com/QwikDev/qwik/blob/main/CONTRIBUTING.md) for more information on how to build Qwik from the source and contribute! ## Related - [Partytown](https://partytown.qwik.dev/): Relocate resource intensive third-party scripts off of the main thread and into a web worker 🎉. - [Mitosis](https://github.com/BuilderIO/mitosis): Write components once, run everywhere. Compiles to Vue, React, Solid, Angular, Svelte, and more. - [Builder](https://github.com/BuilderIO/builder): Drag and drop page builder and CMS for React, Vue, Angular, and more.

special sponsor
Special sponsor Builder.io
sponsors
Company logo
Company logo
================================================ FILE: SECURITY.md ================================================ # Reporting Security Issues The Qwik team and community are dedicated to keeping our project secure, and we appreciate your help in identifying and disclosing security issues responsibly. Your efforts make a big difference! To report a security issue, please use the "[Report a Vulnerability](https://github.com/QwikDev/qwik/security/advisories/new)" tab on our GitHub Security Advisory page. After you submit a report, we'll get back to you with the next steps. We'll keep you updated on our progress towards fixing the issue and any related announcements. If we need more information, we might reach out to you for further details. For security issues in third-party modules, please contact the maintainer of the module directly. Alternatively, you can use the [npm contact form](https://www.npmjs.com/support) and select "I'm reporting a security vulnerability." Thanks for helping us keep Qwik safe and secure! ================================================ FILE: contributing/TRIAGE.md ================================================ # Triage Titans Guide Hey there! Welcome to the wild world of the **Triage Titans**, where we tame bugs and nurture enhancements with the precision of true repository doctors. Let's keep the code healthy, the project smooth, and have some fun along the way. ## Note about tags prefixes: 1. **STATUS-1**: The initial `needs triage` gets automatically added to newly created issues 2. **STATUS-2**: A "waiting for someone/something" status. 3. **STATUS-3**: The final state of an issue. This is a "resolution" status. --- 👇 _Inspiration for the diagrams below came from the Vite project_ ## Bug Triaging Process Our bug triaging process makes sure every reported issue gets the attention it deserves. We categorize, prioritize, and assign bugs to the right person to squash them quickly. Here's how the Triage Titans handle bug reports in the Qwik repository: ```mermaid flowchart TD start{Missing information?} start --YES--> close1[Tag with\n'STATUS-2: missing info'\n\nBot will auto close if\n no update for 14 days] start --NO--> dupe{Is duplicate?} dupe --YES--> close2[Close, point to duplicate\n and tag with\n'STATUS-3: duplication'] dupe --NO--> repro{Has proper\nreproduction?} repro --NO--> close3[Tag with\n 'STATUS-2: needs reproduction'\nBot will auto close if \nno update for 14 days] repro --YES--> real{Is actually a bug?} real --NO--> intended{Is the intended\nbehaviour?} intended --YES--> explain[Explain and close.\nPoint to docs if needed.\nTag with\n'STATUS-3: works as expected'] intended --NO--> open[Tag with\n'STATUS-2: requires discussion'\nand either\n'WAITING FOR: team'\n'WAITING FOR: user'] real --YES--> real2["1. Tag with 'STATUS-2: team is working on this'\n2. Add related feature label if\napplicable (e.g. 'COMP: runtime')\n3. Add priority labels (see below)"] real2 --> unusable{Does the\nbug make Qwik\nunusable?} unusable --YES--> maj{Does the bug\naffect the majority\nof Qwik users?} maj --YES--> P4[P4: urgent] maj --NO--> P3[P3: important] unusable --NO--> workarounds{Are there\nworkarounds for\nthe bug?} workarounds --NO--> P2[P2: minor] workarounds --YES--> P1[P1: nice to have / fix] ``` --- ## Enhancement Triaging Process Alright, Triage Titans! Somebody got a cool new feature idea or an awesome improvement to boost Qwik? It's our job to make sure these enhancements are properly evaluated, prioritized, and brought to life. What helps the team to prioritize work is the number of 👍 votes by the community on a specific issue. ### A note about enhancements to the core: We are very careful about which features we introduce into the Qwik core, because we know that every new feature adds complexity and maintenance tasks to the codebase. Every feature is being carefully evaluated based on our vision and philosophy of "automatic optimization". That's why we'll often encourage the community to implement a certain feature and evaluate its adoption over time to see if it should actually be part of the core. . Now, let's dive into how we handle enhancement requests in the Qwik repository: ```mermaid flowchart TD start{Missing information?} start --YES--> close1[Tag with\n'STATUS-2: missing info'\n\nBot will auto close if\n no update for 14 days] start --NO--> dupe{Is duplicate?} dupe --YES--> close2[Close, point to duplicate\n and tag with\n'STATUS-3: duplication'] dupe --NO--> discussion{Requires further\ndiscussion?} discussion --YES--> close3[Tag with\n 'STATUS-2: requires discussion'\nand 'WAITING FOR: team'\nor 'WAITING FOR: user'] discussion --NO--> implement{Should it be\nimplemented by core?} implement --NO--> community{Should it be implemented\nby the community?} community --YES--> incubate[Close and tag with either\n'STATUS-3: incubation'\nor 'STATUS-2: waiting for community PR'\nand 'COMMUNITY: PR is welcomed'] community --NO--> wontfix[Close and tag with\n'STATUS-3: won't be worked on'] implement --YES--> doimplement["1. Tag with 'STATUS-2: team is working on this'\n2. Add related feature label if\napplicable (e.g. 'COMP: runtime')\n3. Add version \nlabels (e.g. 'VERSION: upcoming major')"] ``` ## Thank You! A big shoutout to all our amazing contributors and Triage Titans! Your dedication, creativity, and hard work help keep Qwik running smoothly and evolving with exciting new features. We wouldn't be able to do it without you 🫶 Thank you for being a part of our journey and making Qwik awesome. Keep up the great work, and let's continue building something amazing together! ================================================ FILE: cspell.json ================================================ { "words": [ "Aboutus", "accumsan", "activedescendant", "adipiscing", "alertdialog", "allowpopups", "Almeida", "amet", "antipattern", "Arcrole", "asynchronicity", "basepath", "bbar", "bbox", "bday", "beforeinput", "bgsound", "Bien", "bindgen", "bivariance", "Bivariant", "Bkxp", "blinkfeatures", "Booleanish", "brotli", "browsermain", "builderio", "buildtime", "bunde", "canonicalize", "cdylib", "cjsx", "Clhb", "clic", "cmps", "codegen", "colcount", "colindex", "colspan", "columnheader", "combobox", "complext", "composability", "consectetur", "contentinfo", "Counteradd", "crossorigin", "ctxt", "datetime", "Dblclick", "Debouncer", "deno", "describedby", "dfdfd", "disableblinkfeatures", "disableguestresize", "disablewebsecurity", "divfixture", "dolor", "dropeffect", "elems", "elit", "elli", "epressed", "errormessage", "espree", "estree", "execa", "extensionless", "extless", "extname", "extnames", "fargs", "Fboth", "flowto", "frontmatter", "gesturechange", "gestureend", "gesturestart", "Gettingstarted", "gmsw", "gridcell", "guestinstance", "hackmd", "Hasher", "haspopup", "Hevery", "hola", "horiz", "hostattrs", "hotspot", "httpreferrer", "idents", "imagesizes", "imagesrcset", "importee", "Indexapi", "inlines", "inlist", "insta", "ipsum", "itemprop", "itsok", "jsxs", "keyof", "keyshortcuts", "Keyup", "kleur", "labelledby", "Layoutapi", "layoutname", "listbox", "listitem", "listitems", "lkei", "Lorem", "manu", "manualmeida", "maxage", "mdast", "mdxjs", "menuitemcheckbox", "menuitemradio", "middlewares", "mimalloc", "misko", "miško", "mjsx", "Mobify", "mondodb", "mpath", "msvc", "msvideo", "mtsx", "multiselectable", "multistatus", "myapp", "napi", "netify", "nodeintegration", "noopen", "noscript", "noserialize", "nosniff", "nothere", "nulll", "objs", "odzdfdfd", "oneline", "onrender", "onscrolling", "onwarn", "outdir", "outfile", "outro", "panose", "partytown", "pathdiff", "pfkgyr", "Pinterest", "posinset", "posix", "prefetching", "prerender", "pretium", "progressbar", "PROPPATCH", "proto", "QACTION", "qcomponent", "Qdata", "qdev", "qerror", "qfunc", "Qhook", "qidle", "qinit", "qkssr", "qprefetch", "qqhook", "qresume", "qrls", "QSLOT", "qsymbol", "quicktime", "qvisible", "qwik", "qwikauth", "qwikcity", "qwikdeps", "qwikdom", "qwikevents", "qwikfy", "qwikify", "qwikjson", "qwikloader", "qwikreact", "radiogroup", "Rctx", "reboostrap", "referrerpolicy", "regs", "rehype", "renderz", "reparse", "replayable", "resumability", "revalidates", "rlib", "Roboto", "roledescription", "rowcount", "rowgroup", "rowheader", "rowindex", "rowspan", "rsplitn", "rsps", "SAMEORIGIN", "SAMESITE", "sdfds", "searchbox", "serde", "Serializability", "setsize", "shouldkebab", "signin", "signout", "sit", "slidein", "slotdefault", "somefn", "somestring", "sourcemaps", "spinbutton", "sref", "sstyle", "stemh", "stemv", "styff", "stylesscopedblue", "stylesscopedgreen", "subdir", "submitcompleted", "svgz", "SWC's", "tablist", "tabpanel", "tagname", "tdblg", "textbox", "Textfromdefault", "threejs", "tlsv", "todoapp", "todos", "treegrid", "treeitem", "treeitems", "treeshake", "treeshaked", "tsdoc", "typecheck", "typeof", "typesafe", "undici", "unist", "unselectable", "unsub", "urlset", "valign", "valuenow", "valuetext", "Vdom", "vfile", "vite", "Vivamus", "Vnode", "Vnodes", "vulputate", "wbmp", "webfont", "webpreferences", "webworker", "wmode", "xlink" ], "enableFiletypes": ["mdx"] } ================================================ FILE: e2e/adapters-e2e/.gitignore ================================================ playwright-report dist logs server tmp ================================================ FILE: e2e/adapters-e2e/adapters/express/vite.config.ts ================================================ import { nodeServerAdapter } from '@builder.io/qwik-city/adapters/node-server/vite'; import { extendConfig } from '@builder.io/qwik-city/vite'; import baseConfig from '../../vite.config'; export default extendConfig(baseConfig, () => { return { build: { ssr: true, rollupOptions: { input: ['src/entry.express.tsx', '@qwik-city-plan'], }, }, plugins: [nodeServerAdapter({ name: 'express' })], }; }); ================================================ FILE: e2e/adapters-e2e/package.json ================================================ { "name": "qwik-buffering-test-app", "description": "Qwik buffering test app", "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "private": true, "scripts": { "build": "qwik build", "build.client": "vite build", "build.preview": "vite build --ssr src/entry.preview.tsx", "build.server": "vite build -c adapters/express/vite.config.ts", "build.types": "tsc --incremental --noEmit", "deploy": "vercel deploy", "dev": "vite --mode ssr", "dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force", "express": "pnpm build && pnpm serve", "fmt": "prettier --write .", "fmt.check": "prettier --check .", "lint": "eslint \"src/**/*.ts*\"", "preview": "qwik build preview && vite preview --open", "qwik": "qwik", "serve": "node server/entry.express", "start": "vite --open --mode ssr", "test": "playwright test", "test.debug": "playwright test --debug", "test.ui": "playwright test --ui" }, "type": "module" } ================================================ FILE: e2e/adapters-e2e/playwright.config.ts ================================================ import { defineConfig, devices } from '@playwright/test'; /** See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ testDir: './tests', fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: 'line', use: { baseURL: 'http://localhost:3000', // trace: 'on-first-retry', // screenshot: 'only-on-failure', // Increase timeouts for service worker operations actionTimeout: 10000, navigationTimeout: 10000, }, // Increase global timeout for service worker tests timeout: process.env.CI ? 120000 : 30000, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'], }, }, // { // name: 'firefox', // use: { ...devices['Desktop Firefox'] }, // }, { name: 'webkit', use: { ...devices['Desktop Safari'] }, }, ], webServer: { command: 'npm run express', port: 3000, stdout: 'pipe', reuseExistingServer: !process.env.CI, timeout: process.env.CI ? 120000 : 30000, }, }); ================================================ FILE: e2e/adapters-e2e/src/components/click-me/click-me.tsx ================================================ import { component$, useSignal } from '@builder.io/qwik'; // We need to extract the component to see the bug on 1.5.7 export default component$(() => { const isOpenSig = useSignal(false); return ( <> {isOpenSig.value &&
Hi 👋
} ); }); ================================================ FILE: e2e/adapters-e2e/src/components/router-head/router-head.tsx ================================================ import { component$ } from '@builder.io/qwik'; import { useDocumentHead, useLocation } from '@builder.io/qwik-city'; export const RouterHead = component$(() => { const head = useDocumentHead(); const loc = useLocation(); return ( <> {head.title} {head.meta.map((m) => ( ))} {head.links.map((l) => ( ))} ); }); ================================================ FILE: e2e/adapters-e2e/src/entry.dev.tsx ================================================ /* * WHAT IS THIS FILE? * * Development entry point using only client-side modules: * - Do not use this mode in production! * - No SSR * - No portion of the application is pre-rendered on the server. * - All of the application is running eagerly in the browser. * - More code is transferred to the browser than in SSR mode. * - Optimizer/Serialization/Deserialization code is not exercised! */ import { render, type RenderOptions } from '@builder.io/qwik'; import Root from './root'; export default function (opts: RenderOptions) { return render(document, , opts); } ================================================ FILE: e2e/adapters-e2e/src/entry.express.tsx ================================================ /* * WHAT IS THIS FILE? * * It's the entry point for the Express HTTP server when building for production. * * Learn more about Node.js server integrations here: * - https://qwik.dev/docs/deployments/node/ * */ import { createQwikCity, type PlatformNode } from '@builder.io/qwik-city/middleware/node'; import 'dotenv/config'; import qwikCityPlan from '@qwik-city-plan'; import { manifest } from '@qwik-client-manifest'; import render from './entry.ssr'; import express from 'express'; import { fileURLToPath } from 'node:url'; import { join } from 'node:path'; declare global { type QwikCityPlatform = PlatformNode; } // Directories where the static assets are located const distDir = join(fileURLToPath(import.meta.url), '..', '..', 'dist'); const buildDir = join(distDir, 'build'); // Allow for dynamic port const PORT = process.env.PORT ?? 3000; // Create the Qwik City Node middleware const { router, notFound } = createQwikCity({ render, qwikCityPlan, manifest, // getOrigin(req) { // // If deploying under a proxy, you may need to build the origin from the request headers // // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto // const protocol = req.headers["x-forwarded-proto"] ?? "http"; // // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host // const host = req.headers["x-forwarded-host"] ?? req.headers.host; // return `${protocol}://${host}`; // } }); // Create the express server // https://expressjs.com/ const app = express(); // Enable gzip compression // app.use(compression()); // Static asset handlers // https://expressjs.com/en/starter/static-files.html app.use(`/build`, express.static(buildDir, { immutable: true, maxAge: '1y' })); app.use(express.static(distDir, { redirect: false })); // Use Qwik City's page and endpoint request handler app.use(router); // Use Qwik City's 404 handler app.use(notFound); // Start the express server app.listen(PORT, () => { /* eslint-disable */ console.log(`Server started: http://localhost:${PORT}/`); }); ================================================ FILE: e2e/adapters-e2e/src/entry.preview.tsx ================================================ /* * WHAT IS THIS FILE? * * It's the bundle entry point for `npm run preview`. * That is, serving your app built in production mode. * * Feel free to modify this file, but don't remove it! * * Learn more about Vite's preview command: * - https://vitejs.dev/config/preview-options.html#preview-options * */ import { createQwikCity } from '@builder.io/qwik-city/middleware/node'; import qwikCityPlan from '@qwik-city-plan'; // make sure qwikCityPlan is imported before entry import render from './entry.ssr'; /** The default export is the QwikCity adapter used by Vite preview. */ export default createQwikCity({ render, qwikCityPlan }); ================================================ FILE: e2e/adapters-e2e/src/entry.ssr.tsx ================================================ /** * WHAT IS THIS FILE? * * SSR entry point, in all cases the application is rendered outside the browser, this entry point * will be the common one. * * - Server (express, cloudflare...) * - Npm run start * - Npm run preview * - Npm run build */ import { renderToStream, type RenderToStreamOptions } from '@builder.io/qwik/server'; import { manifest } from '@qwik-client-manifest'; import Root from './root'; export default function (opts: RenderToStreamOptions) { return renderToStream(, { manifest, ...opts, // Use container attributes to set attributes on the html tag. containerAttributes: { lang: 'en-us', ...opts.containerAttributes, }, // prefetchStrategy: { // implementation: { // linkInsert: "html-append", // linkRel: "modulepreload", // }, // }, serverData: { ...opts.serverData, }, }); } ================================================ FILE: e2e/adapters-e2e/src/root.tsx ================================================ import { component$ } from '@builder.io/qwik'; import { QwikCityProvider, RouterOutlet, ServiceWorkerRegister } from '@builder.io/qwik-city'; import { RouterHead } from './components/router-head/router-head'; export default component$(() => { /** * The root of a QwikCity site always start with the component, immediately * followed by the document's and . * * Don't remove the `` and `` elements. */ return ( {/* */} ); }); ================================================ FILE: e2e/adapters-e2e/src/routes/index.tsx ================================================ import { component$ } from '@builder.io/qwik'; import { type DocumentHead } from '@builder.io/qwik-city'; import ClickMe from '~/components/click-me/click-me'; export default component$(() => { return ( <> go to profile

Home page


{/* We need to extract the component to see the bug on 1.5.7 */} ); }); export const head: DocumentHead = { title: 'Welcome to Qwik', meta: [ { name: 'description', content: 'Qwik site description', }, ], }; ================================================ FILE: e2e/adapters-e2e/src/routes/layout.tsx ================================================ import { component$, Slot } from '@builder.io/qwik'; export default component$(() => { return ; }); ================================================ FILE: e2e/adapters-e2e/src/routes/profile/index.tsx ================================================ import { component$ } from '@builder.io/qwik'; export default component$(() => { return ( <> go to home

Profile page 🙂

); }); ================================================ FILE: e2e/adapters-e2e/src/routes/service-worker.ts ================================================ /* * WHAT IS THIS FILE? * * The service-worker.ts file is used to have state of the art prefetching. * https://qwik.dev/qwikcity/prefetching/overview/ * * Qwik uses a service worker to speed up your site and reduce latency, ie, not used in the traditional way of offline. * You can also use this file to add more functionality that runs in the service worker. */ import { setupServiceWorker } from '@builder.io/qwik-city/service-worker'; setupServiceWorker(); addEventListener('install', () => self.skipWaiting()); addEventListener('activate', () => self.clients.claim()); declare const self: ServiceWorkerGlobalScope; ================================================ FILE: e2e/adapters-e2e/tests/express.spec.ts ================================================ import { expect, test } from '@playwright/test'; test.describe('Verifying Express Adapter', () => { test('should ignore unknown qdata', async ({ page, request }) => { page.goto('/'); const response = await request.post('/?qfunc=ThisDoesNotExist', { headers: { 'X-Qrl': 'ThisDoesNotExist', 'Content-Type': 'application/qwik-json', }, data: { _entry: '2', _objs: ['\u0002_#s_ThisDoesNotExist', 1, ['0', '1']], }, }); await expect(response.status()).toBe(500); // Verify server is still responsive by making another request const healthCheck = await request.get('/'); await expect(healthCheck.ok()).toBeTruthy(); await page.getByRole('link', { name: 'go to profile' }).click(); await expect(page.getByRole('heading', { name: 'Profile page' })).toBeVisible(); }); }); ================================================ FILE: e2e/adapters-e2e/tsconfig.json ================================================ { "compilerOptions": { "baseUrl": ".", "allowJs": true, "target": "ES2020", "module": "ES2022", "lib": ["es2022", "DOM", "WebWorker", "DOM.Iterable"], "jsx": "react-jsx", "jsxImportSource": "@builder.io/qwik", "strict": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "moduleResolution": "Bundler", "esModuleInterop": true, "skipLibCheck": true, "incremental": true, "isolatedModules": true, "outDir": "tmp", "noEmit": true, "paths": { "~/*": ["./src/*"] } }, "include": ["src", "./*.d.ts", "./*.config.ts"] } ================================================ FILE: e2e/adapters-e2e/vite.config.ts ================================================ /** * This is the base config for vite. When building, the adapter config is used which loads this file * and extends it. */ import { qwikCity } from '@builder.io/qwik-city/vite'; import { qwikVite } from '@builder.io/qwik/optimizer'; import { defineConfig, type UserConfig } from 'vite'; import tsconfigPaths from 'vite-tsconfig-paths'; import pkg from './package.json'; type PkgDep = Record; const { dependencies = {}, devDependencies = {} } = pkg as any as { dependencies: PkgDep; devDependencies: PkgDep; [key: string]: unknown; }; errorOnDuplicatesPkgDeps(devDependencies, dependencies); /** * Note that Vite normally starts from `index.html` but the qwikCity plugin makes start at * `src/entry.ssr.tsx` instead. */ export default defineConfig((): UserConfig => { return { plugins: [qwikCity(), qwikVite(), tsconfigPaths({ root: '.' })], // This tells Vite which dependencies to pre-build in dev mode. optimizeDeps: { // Put problematic deps that break bundling here, mostly those with binaries. // For example ['better-sqlite3'] if you use that in server functions. exclude: [], }, /** * This is an advanced setting. It improves the bundling of your server code. To use it, make * sure you understand when your consumed packages are dependencies or dev dependencies. * (otherwise things will break in production) */ // ssr: // command === "build" && mode === "production" // ? { // // All dev dependencies should be bundled in the server build // noExternal: Object.keys(devDependencies), // // Anything marked as a dependency will not be bundled // // These should only be production binary deps (including deps of deps), CLI deps, and their module graph // // If a dep-of-dep needs to be external, add it here // // For example, if something uses `bcrypt` but you don't have it as a dep, you can write // // external: [...Object.keys(dependencies), 'bcrypt'] // external: Object.keys(dependencies), // } // : undefined, server: { headers: { // Don't cache the server response in dev mode 'Cache-Control': 'public, max-age=0', }, }, preview: { headers: { // Do cache the server response in preview (non-adapter production build) 'Cache-Control': 'public, max-age=360', }, }, }; }); // *** utils *** /** * Function to identify duplicate dependencies and throw an error * * @param {Object} devDependencies - List of development dependencies * @param {Object} dependencies - List of production dependencies */ function errorOnDuplicatesPkgDeps(devDependencies: PkgDep, dependencies: PkgDep) { let msg = ''; // Create an array 'duplicateDeps' by filtering devDependencies. // If a dependency also exists in dependencies, it is considered a duplicate. const duplicateDeps = Object.keys(devDependencies).filter((dep) => dependencies[dep]); // include any known qwik packages const qwikPkg = Object.keys(dependencies).filter((value) => /qwik/i.test(value)); // any errors for missing "qwik-city-plan" // [PLUGIN_ERROR]: Invalid module "@qwik-city-plan" is not a valid package msg = `Move qwik packages ${qwikPkg.join(', ')} to devDependencies`; if (qwikPkg.length > 0) { throw new Error(msg); } // Format the error message with the duplicates list. // The `join` function is used to represent the elements of the 'duplicateDeps' array as a comma-separated string. msg = ` Warning: The dependency "${duplicateDeps.join(', ')}" is listed in both "devDependencies" and "dependencies". Please move the duplicated dependencies to "devDependencies" only and remove it from "dependencies" `; // Throw an error with the constructed message. if (duplicateDeps.length > 0) { throw new Error(msg); } } ================================================ FILE: e2e/docs-e2e/.gitignore ================================================ # Playwright node_modules/ /test-results/ /playwright-report/ /blob-report/ /playwright/.cache/ ================================================ FILE: e2e/docs-e2e/package.json ================================================ { "name": "docs-e2e", "description": "", "private": true, "author": "", "devDependencies": { "@playwright/test": "1.54.1", "@types/node": "20.19.0" }, "keywords": [], "license": "ISC", "main": "index.js", "scripts": { "test": "pnpm exec playwright test --config=playwright.config.ts --project=chromium", "test-ui": "pnpm exec playwright test --config=playwright.config.ts --project=chromium --ui" }, "type": "commonjs" } ================================================ FILE: e2e/docs-e2e/playwright.config.ts ================================================ import { defineConfig, devices } from '@playwright/test'; /** Read environment variables from file. https://github.com/motdotla/dotenv */ // import dotenv from 'dotenv'; // import path from 'path'; // dotenv.config({ path: path.resolve(__dirname, '.env') }); /** See https://playwright.dev/docs/test-configuration. */ const TestingURL = 'http://127.0.0.1:3000'; export default defineConfig({ testDir: './tests', /* Global timeout for each test */ timeout: 60_000, expect: { timeout: 60_000 }, /* Run tests in files in parallel */ fullyParallel: true, /* Fail the build on CI if you accidentally left test.only in the source code. */ forbidOnly: !!process.env.CI, /* Retry on CI only */ retries: process.env.CI ? 2 : 0, /* Opt out of parallel tests on CI. */ workers: process.env.CI ? 1 : undefined, /* Reporter to use. See https://playwright.dev/docs/test-reporters */ reporter: 'html', /* Shared settings for all the projects below. See https://playwright.dev/docs/api/class-testoptions. */ use: { /* Base URL to use in actions like `await page.goto('/')`. */ baseURL: TestingURL, actionTimeout: 30_000, navigationTimeout: 60_000, /* Collect trace when retrying the failed test. See https://playwright.dev/docs/trace-viewer */ trace: 'on-first-retry', }, /* Configure projects for major browsers */ projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'] }, }, { name: 'chrome', use: { ...devices['Desktop Chrome'] }, }, { name: 'firefox', use: { ...devices['Desktop Firefox'] }, }, { name: 'webkit', use: { ...devices['Desktop Safari'] }, }, /* Test against mobile viewports. */ // { // name: 'Mobile Chrome', // use: { ...devices['Pixel 5'] }, // }, // { // name: 'Mobile Safari', // use: { ...devices['iPhone 12'] }, // }, /* Test against branded browsers. */ // { // name: 'Microsoft Edge', // use: { ...devices['Desktop Edge'], channel: 'msedge' }, // }, // { // name: 'Google Chrome', // use: { ...devices['Desktop Chrome'], channel: 'chrome' }, // }, ], /* Run your local dev server before starting the tests */ webServer: { command: 'pnpm -C ../../ run docs.dev', url: TestingURL, reuseExistingServer: !process.env.CI, }, }); ================================================ FILE: e2e/docs-e2e/tests/Docs/advanced-pages-load.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('Advanced Dollar Function page loads', async ({ page }) => { await page.goto('/docs/advanced/dollar/'); await expect(page).toHaveTitle('The $ dollar sign | Advanced 📚 Qwik Documentation'); }); test('Advanced Containers page loads', async ({ page }) => { await page.goto('/docs/advanced/containers/'); await expect(page).toHaveTitle('Containers | Advanced 📚 Qwik Documentation'); }); test('Advanced QRL page loads', async ({ page }) => { await page.goto('/docs/advanced/qrl/'); await expect(page).toHaveTitle('QRL | Advanced 📚 Qwik Documentation'); }); test('Advanced Library page loads', async ({ page }) => { await page.goto('/docs/advanced/library/'); await expect(page).toHaveTitle('Component library | Advanced 📚 Qwik Documentation'); }); test('Advanced Qwikloader page loads', async ({ page }) => { await page.goto('/docs/advanced/qwikloader/'); await expect(page).toHaveTitle('Qwikloader | Advanced 📚 Qwik Documentation'); }); test('Advanced Optimizer page loads', async ({ page }) => { await page.goto('/docs/advanced/optimizer/'); await expect(page).toHaveTitle('Optimizer Rules | Advanced 📚 Qwik Documentation'); }); test('Advanced Prefetching Modules page loads', async ({ page }) => { await page.goto('/docs/advanced/modules-prefetching/'); await expect(page).toHaveTitle('Prefetching | Advanced 📚 Qwik Documentation'); }); test('Advanced Custom Build Directory page loads', async ({ page }) => { await page.goto('/docs/advanced/custom-build-dir/'); await expect(page).toHaveTitle('Custom Build Output Directory | Advanced 📚 Qwik Documentation'); }); test('Advanced Vite page loads', async ({ page }) => { await page.goto('/docs/advanced/vite/'); await expect(page).toHaveTitle('Vite | Advanced 📚 Qwik Documentation'); }); test('Advanced Routing page loads', async ({ page }) => { await page.goto('/docs/advanced/routing/'); await expect(page).toHaveTitle('Advanced Routing | Qwik City 📚 Qwik Documentation'); }); test('Advanced Plugins page loads', async ({ page }) => { await page.goto('/docs/advanced/plugins/'); await expect(page).toHaveTitle('Qwik Plugins | Qwik City 📚 Qwik Documentation'); }); test('Advanced Request Handling page loads', async ({ page }) => { await page.goto('/docs/advanced/request-handling/'); await expect(page).toHaveTitle('Request Handling | Advanced 📚 Qwik Documentation'); }); test('Advanced Speculative Module Fetching page loads', async ({ page }) => { await page.goto('/docs/advanced/speculative-module-fetching/'); await expect(page).toHaveTitle('Speculative Module Fetching | Advanced 📚 Qwik Documentation'); }); test('Advanced Menu page loads', async ({ page }) => { await page.goto('/docs/advanced/menu/'); await expect(page).toHaveTitle('Menu | Advanced 📚 Qwik Documentation'); }); test('Advanced Generating Sitemaps page loads', async ({ page }) => { await page.goto('/docs/advanced/sitemaps/'); await expect(page).toHaveTitle('Generating Sitemaps | Advanced 📚 Qwik Documentation'); }); test('Advanced ESLint-Rules page loads', async ({ page }) => { await page.goto('/docs/advanced/eslint/'); // currently does not have a custom title await expect(page).toHaveTitle('Qwik - Framework reimagined for the edge'); }); test('Advanced Content Security Policy page loads', async ({ page }) => { await page.goto('/docs/advanced/content-security-policy/'); await expect(page).toHaveTitle('Content Security Policy | Advanced 📚 Qwik Documentation'); }); test('Advanced Complex Forms page loads', async ({ page }) => { await page.goto('/docs/advanced/complex-forms/'); await expect(page).toHaveTitle('Complex Forms | Advanced 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/community-pages.load.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('Community Projects page loads', async ({ page }) => { await page.goto('/community/projects/'); await expect(page).toHaveTitle('Projects | Qwik Community 📚 Qwik Documentation'); }); test('Community Groups page loads', async ({ page }) => { await page.goto('/community/groups/'); await expect(page).toHaveTitle('Groups | Qwik Community 📚 Qwik Documentation'); }); test('Community Values page loads', async ({ page }) => { await page.goto('/community/values/'); await expect(page).toHaveTitle('Values | Qwik Community 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/concepts-pages-laod.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('Concepts Think Qwik page loads', async ({ page }) => { await page.goto('/docs/concepts/think-qwik/'); await expect(page).toHaveTitle('Think Qwik | Concepts 📚 Qwik Documentation'); }); test('Concepts Resumable page loads', async ({ page }) => { await page.goto('/docs/concepts/resumable/'); await expect(page).toHaveTitle('Resumable | Concepts 📚 Qwik Documentation'); }); test('Concepts Progressive page loads', async ({ page }) => { await page.goto('/docs/concepts/progressive/'); await expect(page).toHaveTitle('Progressive | Concepts 📚 Qwik Documentation'); }); test('Concepts Reactivity page loads', async ({ page }) => { await page.goto('/docs/concepts/reactivity/'); await expect(page).toHaveTitle('Reactivity | Concepts 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/cookbook-pages-load.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('Cookbook Overview page loads', async ({ page }) => { await page.goto('/docs/cookbook/'); await expect(page).toHaveTitle('Cookbook | Overview 📚 Qwik Documentation'); }); test('Cookbook Algolia Search page loads', async ({ page }) => { await page.goto('/docs/cookbook/algolia-search/'); await expect(page).toHaveTitle('Cookbook | Algolia Search 📚 Qwik Documentation'); }); test('Cookbook Combine Request Handlers page loads', async ({ page }) => { await page.goto('/docs/cookbook/combine-request-handlers/'); await expect(page).toHaveTitle('Cookbook | Combine Request Handlers 📚 Qwik Documentation'); }); test('Cookbook Debouncer page loads', async ({ page }) => { await page.goto('/docs/cookbook/debouncer/'); await expect(page).toHaveTitle('Cookbook | Debouncer 📚 Qwik Documentation'); }); test('Cookbook Fonts page loads', async ({ page }) => { await page.goto('/docs/cookbook/fonts/'); await expect(page).toHaveTitle('Cookbook | Font optimization 📚 Qwik Documentation'); }); test('Cookbook Glob Import & Dynamic Import page loads', async ({ page }) => { await page.goto('/docs/cookbook/glob-import/'); await expect(page).toHaveTitle( 'Cookbook | Glob Import with import.meta.glob 📚 Qwik Documentation' ); }); test('Cookbook NavLink Component page loads', async ({ page }) => { await page.goto('/docs/cookbook/nav-link/'); await expect(page).toHaveTitle('Cookbook | Navbar link 📚 Qwik Documentation'); }); test('Cookbook Deploy with Node using Docker page loads', async ({ page }) => { await page.goto('/docs/cookbook/node-docker-deploy/'); await expect(page).toHaveTitle('Cookbook | Deploy with Node using Docker 📚 Qwik Documentation'); }); test('Cookbook Portals page loads', async ({ page }) => { await page.goto('/docs/cookbook/portals/'); await expect(page).toHaveTitle('Cookbook | Portals 📚 Qwik Documentation'); }); test('Cookbook Streaming/deferred loaders page loads', async ({ page }) => { await page.goto('/docs/cookbook/streaming-deferred-loaders/'); await expect(page).toHaveTitle('Cookbook | Streaming/deferred loaders 📚 Qwik Documentation'); }); test('Cookbook sync$ Events page loads', async ({ page }) => { await page.goto('/docs/cookbook/sync-events/'); await expect(page).toHaveTitle('Cookbook | Synchronous Events with State 📚 Qwik Documentation'); }); test('Cookbook Theme Management page loads', async ({ page }) => { await page.goto('/docs/cookbook/theme-management/'); await expect(page).toHaveTitle('Cookbook | Dark and Light Theme 📚 Qwik Documentation'); }); test('Cookbook Drag & Drop page loads', async ({ page }) => { await page.goto('/docs/cookbook/drag&drop/'); await expect(page).toHaveTitle('Cookbook | Drag & Drop 📚 Qwik Documentation'); }); test('Cookbook View Transition API page loads', async ({ page }) => { await page.goto('/docs/cookbook/view-transition/'); await expect(page).toHaveTitle('Cookbook | View Transition API 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/deployments-pages-load.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('Deployments Overview page loads', async ({ page }) => { await page.goto('/docs/deployments/'); await expect(page).toHaveTitle('Deployments | Guides 📚 Qwik Documentation'); }); test('Deployments Azure Static Web Apps Middleware page loads', async ({ page }) => { await page.goto('/docs/deployments/azure-swa/'); await expect(page).toHaveTitle('Azure Static Web Apps | Deployments 📚 Qwik Documentation'); }); test('Deployments AWS Adapter page loads', async ({ page }) => { await page.goto('/docs/deployments/aws-lambda/'); await expect(page).toHaveTitle('AWS Lambda | Deployments 📚 Qwik Documentation'); }); test('Deployments Firebase Adapter page loads', async ({ page }) => { await page.goto('/docs/deployments/firebase/'); await expect(page).toHaveTitle('Firebase | Deployments 📚 Qwik Documentation'); }); test('Deployments Google Cloud Run Middleware page loads', async ({ page }) => { await page.goto('/docs/deployments/gcp-cloud-run/'); await expect(page).toHaveTitle('Cloud Run Middleware | Deployments 📚 Qwik Documentation'); }); test('Deployments Cloudflare Pages Adapter page loads', async ({ page }) => { await page.goto('/docs/deployments/cloudflare-pages/'); await expect(page).toHaveTitle( 'Cloudflare Pages Adapter and Middleware | Deployments 📚 Qwik Documentation' ); }); test('Deployments Cloudflare Workers Adapter page loads', async ({ page }) => { await page.goto('/docs/deployments/cloudflare-workers/'); await expect(page).toHaveTitle( 'Cloudflare Workers Adapter and Middleware | Deployments 📚 Qwik Documentation' ); }); test('Deployments Deno Middleware page loads', async ({ page }) => { await page.goto('/docs/deployments/deno/'); await expect(page).toHaveTitle('Deno Middleware | Deployments 📚 Qwik Documentation'); }); test('Deployments Bun Middleware page loads', async ({ page }) => { await page.goto('/docs/deployments/bun/'); await expect(page).toHaveTitle('Bun Middleware | Deployments 📚 Qwik Documentation'); }); test('Deployments Netlify Edge Adapter page loads', async ({ page }) => { await page.goto('/docs/deployments/netlify-edge/'); await expect(page).toHaveTitle( 'Netlify Edge Adapter and Middleware | Deployments 📚 Qwik Documentation' ); }); test('Deployments Node Middleware page loads', async ({ page }) => { await page.goto('/docs/deployments/node/'); await expect(page).toHaveTitle('Node Middleware | Deployments 📚 Qwik Documentation'); }); test('Deployments Vercel Edge Adapter page loads', async ({ page }) => { await page.goto('/docs/deployments/vercel-edge/'); await expect(page).toHaveTitle( 'Vercel Edge Adapter and Middleware | Deployments 📚 Qwik Documentation' ); }); test('Deployments Static Site Adapter page loads', async ({ page }) => { await page.goto('/docs/deployments/static/'); await expect(page).toHaveTitle('Static Site 📚 Qwik Documentation'); }); test('Deployments GitHub Pages Adapter page loads', async ({ page }) => { await page.goto('/docs/deployments/github-pages/'); await expect(page).toHaveTitle('GitHub Pages 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/docs-components-pages-load.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('Components Overview page loads', async ({ page }) => { await page.goto('/docs/core/overview/'); await expect(page).toHaveTitle('Overview | Components 📚 Qwik Documentation'); }); test('Components State page loads', async ({ page }) => { await page.goto('/docs/core/state/'); await expect(page).toHaveTitle('State | Components 📚 Qwik Documentation'); }); test('Components Tasks and Lifecycle page loads', async ({ page }) => { await page.goto('/docs/core/tasks/'); await expect(page).toHaveTitle('Tasks and Lifecycle | Components 📚 Qwik Documentation'); }); test('Components Context page loads', async ({ page }) => { await page.goto('/docs/core/context/'); await expect(page).toHaveTitle('Context | Components 📚 Qwik Documentation'); }); test('Components Slots page loads', async ({ page }) => { await page.goto('/docs/core/slots/'); await expect(page).toHaveTitle('Slots | Components 📚 Qwik Documentation'); }); test('Components Rendering page loads', async ({ page }) => { await page.goto('/docs/core/rendering/'); await expect(page).toHaveTitle('Rendering | Components 📚 Qwik Documentation'); }); test('Components Styles page loads', async ({ page }) => { await page.goto('/docs/core/styles/'); await expect(page).toHaveTitle('Styles | Components 📚 Qwik Documentation'); }); test('Components API Reference page loads', async ({ page }) => { await page.goto('/api/qwik/'); // todo V2: change this to @qwik.dev await expect(page).toHaveTitle('@builder.io/qwik API Reference 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/guides-pages-load.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('Guides Qwik in a nutshell page loads', async ({ page }) => { await page.goto('/docs/guides/qwik-nutshell/'); await expect(page).toHaveTitle('Qwik in a nutshell | Introduction 📚 Qwik Documentation'); }); test('Guides MDX page loads', async ({ page }) => { await page.goto('/docs/guides/mdx/'); await expect(page).toHaveTitle('Markdown and MDX | Guides 📚 Qwik Documentation'); }); test('Guides SSG page loads', async ({ page }) => { await page.goto('/docs/guides/static-site-generation/'); await expect(page).toHaveTitle( 'Static Site Generation (SSG) Overview | Guides 📚 Qwik Documentation' ); }); test('Guides Capacitor page loads', async ({ page }) => { await page.goto('/docs/guides/capacitor/'); await expect(page).toHaveTitle('Qwik Hybrid Native App Overview | Guides 📚 Qwik Documentation'); }); test('Guides React Cheat Sheet page loads', async ({ page }) => { await page.goto('/docs/guides/react-cheat-sheet/'); await expect(page).toHaveTitle('Qwik for React developers 📚 Qwik Documentation'); }); test('Guides Best Practices page loads', async ({ page }) => { await page.goto('/docs/guides/best-practices/'); await expect(page).toHaveTitle('Best Practices | Guides 📚 Qwik Documentation'); }); test('Guides Bundle Optimization page loads', async ({ page }) => { await page.goto('/docs/guides/bundle/'); await expect(page).toHaveTitle('Bundle Optimization | Guides 📚 Qwik Documentation'); }); test('Guides Environment Variables page loads', async ({ page }) => { await page.goto('/docs/guides/env-variables/'); await expect(page).toHaveTitle('Environment variables | Qwik City 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/integrations-pages-load.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('Integrations Overview page loads', async ({ page }) => { await page.goto('/docs/integrations/'); await expect(page).toHaveTitle('Qwik City Integrations | Guides 📚 Qwik Documentation'); }); test('Integrations Astro page loads', async ({ page }) => { await page.goto('/docs/integrations/astro/'); await expect(page).toHaveTitle('Astro | Integrations 📚 Qwik Documentation'); }); test('Integrations Auth.js page loads', async ({ page }) => { await page.goto('/docs/integrations/authjs/'); await expect(page).toHaveTitle('Auth.js | Integrations 📚 Qwik Documentation'); }); test('Integrations Bootstrap page loads', async ({ page }) => { await page.goto('/docs/integrations/bootstrap/'); await expect(page).toHaveTitle('Bootstrap | Integrations 📚 Qwik Documentation'); }); test('Integrations Builder.io page loads', async ({ page }) => { await page.goto('/docs/integrations/builderio/'); await expect(page).toHaveTitle('Builder.io | Integrations 📚 Qwik Documentation'); }); test('Integrations Cypress page loads', async ({ page }) => { await page.goto('/docs/integrations/cypress/'); await expect(page).toHaveTitle('Cypress | Integrations 📚 Qwik Documentation'); }); test('Integrations Drizzle page loads', async ({ page }) => { await page.goto('/docs/integrations/drizzle/'); await expect(page).toHaveTitle('Drizzle | Integrations 📚 Qwik Documentation'); }); test('Integrations Internationalization page loads', async ({ page }) => { await page.goto('/docs/integrations/i18n/'); await expect(page).toHaveTitle('Internationalization | Integrations 📚 Qwik Documentation'); }); test('Integrations Icons page loads', async ({ page }) => { await page.goto('/docs/integrations/icons/'); await expect(page).toHaveTitle('Icons | Integrations 📚 Qwik Documentation'); }); test('Integrations Image Optimization page loads', async ({ page }) => { await page.goto('/docs/integrations/image-optimization/'); await expect(page).toHaveTitle('Image Optimization | Integrations 📚 Qwik Documentation'); }); test('Integrations LeafletJS Map page loads', async ({ page }) => { await page.goto('/docs/integrations/leaflet-map/'); await expect(page).toHaveTitle('LeafletJS Map | Integrations 📚 Qwik Documentation'); }); test('Integrations Modular Forms page loads', async ({ page }) => { await page.goto('/docs/integrations/modular-forms/'); await expect(page).toHaveTitle('Modular Forms | Integrations 📚 Qwik Documentation'); }); test('Integrations Nx and enterprise scale monorepos page loads', async ({ page }) => { await page.goto('/docs/integrations/nx/'); await expect(page).toHaveTitle('Nx Monorepos | Integrations 📚 Qwik Documentation'); }); test('Integrations OG Image / Open Graph Image page loads', async ({ page }) => { await page.goto('/docs/integrations/og-img/'); await expect(page).toHaveTitle('OG Image (og-img) | Integrations 📚 Qwik Documentation'); }); test('Integrations Orama page loads', async ({ page }) => { await page.goto('/docs/integrations/orama/'); await expect(page).toHaveTitle('Qwik City and Orama 📚 Qwik Documentation'); }); test('Integrations Panda CSS page loads', async ({ page }) => { await page.goto('/docs/integrations/panda-css/'); await expect(page).toHaveTitle('Panda CSS | Integrations 📚 Qwik Documentation'); }); test('Integrations Partytown page loads', async ({ page }) => { await page.goto('/docs/integrations/partytown/'); await expect(page).toHaveTitle('Partytown | Integrations 📚 Qwik Documentation'); }); test('Integrations Playwright page loads', async ({ page }) => { await page.goto('/docs/integrations/playwright/'); await expect(page).toHaveTitle('Playwright | Integrations 📚 Qwik Documentation'); }); test('Integrations PostCSS page loads', async ({ page }) => { await page.goto('/docs/integrations/postcss/'); await expect(page).toHaveTitle('PostCSS | Integrations 📚 Qwik Documentation'); }); test('Integrations Prisma page loads', async ({ page }) => { await page.goto('/docs/integrations/prisma/'); await expect(page).toHaveTitle('Prisma | Integrations 📚 Qwik Documentation'); }); test('Integrations Qwik React page loads', async ({ page }) => { await page.goto('/docs/integrations/react/'); await expect(page).toHaveTitle('React | Integrations 📚 Qwik Documentation'); }); test('Integrations Storybook page loads', async ({ page }) => { await page.goto('/docs/integrations/storybook/'); await expect(page).toHaveTitle('Storybook | Integrations 📚 Qwik Documentation'); }); test('Integrations Styled Vanilla Extract page loads', async ({ page }) => { await page.goto('/docs/integrations/styled-vanilla-extract/'); await expect(page).toHaveTitle('Styled Vanilla Extract | Integrations 📚 Qwik Documentation'); }); test('Integrations Supabase page loads', async ({ page }) => { await page.goto('/docs/integrations/supabase/'); await expect(page).toHaveTitle('Supabase | Integrations 📚 Qwik Documentation'); }); test('Integrations Tailwind page loads', async ({ page }) => { await page.goto('/docs/integrations/tailwind/'); await expect(page).toHaveTitle('Tailwind | Integrations 📚 Qwik Documentation'); }); test('Integrations Tauri page loads', async ({ page }) => { await page.goto('/docs/integrations/tauri/'); await expect(page).toHaveTitle('Tauri | Integrations 📚 Qwik Documentation'); }); test('Integrations Turso page loads', async ({ page }) => { await page.goto('/docs/integrations/turso/'); await expect(page).toHaveTitle('Turso | Integrations 📚 Qwik Documentation'); }); test('Integrations Vitest page loads', async ({ page }) => { await page.goto('/docs/integrations/vitest/'); await expect(page).toHaveTitle('Vitest | Integrations 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/navBarOnMobile.spec.ts ================================================ import { test, expect, devices } from '@playwright/test'; test.use({ ...devices['iPhone 13'], }); test('navbar on mobile', async ({ page }) => { await page.goto('/'); const openIcon = page.locator('.mobile-menu > .more-icon > svg'); const closeIcon = page.locator('.mobile-menu > .close-icon > svg'); const navToolKit = page.locator('.menu-toolkit'); const body = page.locator('body'); expect(body).not.toHaveClass('header-open'); await expect(openIcon).toBeVisible(); await openIcon.click(); expect(body).toHaveClass('header-open'); await expect(closeIcon).toBeVisible(); await expect(navToolKit).toBeVisible(); const menuItems = await page.locator('.menu-toolkit > li > a').allTextContents(); const expectedMenuLinks = [ 'Docs', 'Ecosystem', 'Tutorial', 'Qwik Sandbox', 'Blog', 'GitHub', '@QwikDev', 'Discord', ]; expect(menuItems).toStrictEqual(expectedMenuLinks); await closeIcon.click(); expect(body).not.toHaveClass('header-open'); await expect(closeIcon).not.toBeVisible(); await expect(openIcon).toBeVisible(); await expect(navToolKit).not.toBeVisible(); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/pages-load-test.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('home page loads', async ({ page }) => { await page.goto('/'); await expect(page).toHaveTitle('Framework reimagined for the edge! 📚 Qwik Documentation'); }); test('docs page loads', async ({ page }) => { await page.goto('/docs/'); await expect(page).toHaveTitle('Overview | Introduction 📚 Qwik Documentation'); const introductionLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Introduction")) ul li a') .allTextContents(); const expectedIntroductionLinks = ['Overview', 'Getting Started', 'Project structure', 'FAQ']; expect(introductionLinksOnPage).toStrictEqual(expectedIntroductionLinks); const componentsLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Components")) ul li a') .allTextContents(); const expectedComponentLinks = [ 'Overview', 'State', 'Events', 'Tasks & Lifecycle', 'Context', 'Slots', 'Rendering', 'Styling', 'API Reference', ]; expect(componentsLinksOnPage).toStrictEqual(expectedComponentLinks); const qwikCityLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Qwik City")) ul li a') .allTextContents(); const expectedQwikCityLinks = [ 'Overview', 'Routing', 'Pages', 'Layouts', 'Loaders', 'Actions', 'Validators', 'Endpoints', 'Middleware', 'server$', 'Error handling', 'Re-exporting loaders', 'Caching', 'HTML attributes', 'API reference', ]; expect(qwikCityLinksOnPage).toStrictEqual(expectedQwikCityLinks); const cookbookLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Cookbook")) ul li a') .allTextContents(); const expectedCookbookLinks = [ 'Overview', 'Algolia Search', 'Combine Handlers', 'Debouncer', 'Fonts', 'Glob Import', 'Media Controller', 'NavLink', 'Node Docker deploy', 'Portals', 'Streaming loaders', 'Sync events w state', 'Theme Management', 'Drag & Drop', 'View Transition', ]; // if you are adding a new page to the cookbook, please add a new test for the page to load too expect(cookbookLinksOnPage).toStrictEqual(expectedCookbookLinks); const integrationsLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Integrations")) ul li a') .allTextContents(); const expectedIntegrationsLinks = [ 'Overview', 'Astro', 'Auth.js', 'Bootstrap', 'Builder.io', 'Cypress', 'Drizzle', 'i18n', 'Icons', 'Image Optimization', 'Leaflet Map', 'Modular Forms', 'Nx Monorepos', 'OG Image', 'Orama', 'Panda CSS', 'Partytown', 'Playwright', 'PostCSS', 'Prisma', 'React', 'Storybook', 'Styled Vanilla Extract', 'Supabase', 'Tailwind', 'Tauri', 'Turso', 'Vitest', ]; expect(integrationsLinksOnPage).toStrictEqual(expectedIntegrationsLinks); const deploymentsLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Deployments")) ul li a') .allTextContents(); const expectedDeploymentsLinks = [ 'Overview', 'Azure SWA', 'AWS', 'Firebase', 'Google Cloud Run', 'Cloudflare Pages', 'Cloudflare Workers', 'Deno', 'Bun', 'Netlify Edge', 'Node', 'Self-Hosting', 'Vercel Edge', 'Static Site', 'Azion', ]; expect(deploymentsLinksOnPage).toStrictEqual(expectedDeploymentsLinks); const guidesLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Guides")) ul li a') .allTextContents(); const expectedGuidesLinks = [ 'Qwik in a nutshell', 'Markdown & MDX', 'SSG', 'Qwik Native Apps', 'React Cheat Sheet', 'Debugging', 'Best Practices', 'Bundle Optimization', 'Env variables', ]; expect(guidesLinksOnPage).toStrictEqual(expectedGuidesLinks); const conceptsLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Concepts")) ul li a') .allTextContents(); const expectedConceptsLinks = ['Think Qwik', 'Resumable', 'Progressive', 'Reactivity']; expect(conceptsLinksOnPage).toStrictEqual(expectedConceptsLinks); const advancedLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Advanced")) ul li a') .allTextContents(); const expectedAdvancedLinks = [ 'The $ dollar sign', 'Containers', 'QRL', 'Library mode', 'Qwikloader', 'Optimizer', 'Modules Prefetching', 'Build Directory', 'Vite', 'Advanced Routing', 'Qwik Plugins', 'Request Handling', 'Speculative Module Fetching', 'Menus', 'Static Assets', 'Sitemaps', 'ESLint-Rules', 'Content Security Policy', 'Complex Forms', ]; expect(advancedLinksOnPage).toStrictEqual(expectedAdvancedLinks); const referenceLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Reference")) ul li a') .allTextContents(); const expectedReferenceLinks = ['API Reference', 'Deprecated Features']; expect(referenceLinksOnPage).toStrictEqual(expectedReferenceLinks); const qwikLabsLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Qwik Labs 🧪")) ul li a') .allTextContents(); const expectedQwikLabsLinks = [ 'Overview', 'Insights', 'Typed Routes', 'Devtools', 'usePreventNavigate', ]; expect(qwikLabsLinksOnPage).toStrictEqual(expectedQwikLabsLinks); const communityLinksOnPage = await page .locator('#qwik-sidebar') .locator('details:has(summary h5:text("Community")) ul li a') .allTextContents(); const expectedCommunityLinks = ['GitHub', '@QwikDev', 'Discord', 'Community Projects', 'Values']; expect(communityLinksOnPage).toStrictEqual(expectedCommunityLinks); }); test('getting started page loads', async ({ page }) => { await page.goto('/docs/getting-started/'); await expect(page).toHaveTitle('Getting Started | Introduction 📚 Qwik Documentation'); }); test('Project Structure page loads', async ({ page }) => { await page.goto('/docs/project-structure/'); await expect(page).toHaveTitle('Project Structure | Qwik City 📚 Qwik Documentation'); }); test('FAQ page loads', async ({ page }) => { await page.goto('/docs/faq/'); await expect(page).toHaveTitle('Frequently Asked Questions | Introduction 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/qwik-city-pages-load.spec.ts ================================================ // todo V2: rename file to qwik-router-pages-load.spec.ts // todo V2: replace all instances of Qwik City with Qwik Router import { test, expect } from '@playwright/test'; test('Qwik City Overview page loads', async ({ page }) => { await page.goto('/docs/qwikcity/'); await expect(page).toHaveTitle('Overview | Qwik City 📚 Qwik Documentation'); }); test('Qwik City Routing page loads', async ({ page }) => { await page.goto('/docs/routing/'); await expect(page).toHaveTitle('Routing | Qwik City 📚 Qwik Documentation'); }); test('Qwik City Pages page loads', async ({ page }) => { await page.goto('/docs/pages/'); await expect(page).toHaveTitle('Pages | Qwik City 📚 Qwik Documentation'); }); test('Qwik City Layout page loads', async ({ page }) => { await page.goto('/docs/layout/'); await expect(page).toHaveTitle('Layout & Middleware | Guides 📚 Qwik Documentation'); }); test('Qwik City Route Loader page loads', async ({ page }) => { await page.goto('/docs/route-loader/'); await expect(page).toHaveTitle('RouteLoader$ | Qwik City 📚 Qwik Documentation'); }); test('Qwik City Route Action page loads', async ({ page }) => { await page.goto('/docs/action/'); await expect(page).toHaveTitle('RouteAction$ | QwikCity 📚 Qwik Documentation'); }); test('Qwik City Endpoints page loads', async ({ page }) => { await page.goto('/docs/endpoints/'); await expect(page).toHaveTitle('Endpoints | Qwik City 📚 Qwik Documentation'); }); test('Qwik City Middleware page loads', async ({ page }) => { await page.goto('/docs/middleware/'); await expect(page).toHaveTitle('Middleware | Guides 📚 Qwik Documentation'); }); test('Qwik City server$ page loads', async ({ page }) => { await page.goto('/docs/server$/'); await expect(page).toHaveTitle('server$ | Qwik City 📚 Qwik Documentation'); }); test('Qwik City Error Handling page loads', async ({ page }) => { await page.goto('/docs/error-handling/'); await expect(page).toHaveTitle('Error handling | Qwik City 📚 Qwik Documentation'); }); test('Qwik City Re-exporting Loaders page loads', async ({ page }) => { await page.goto('/docs/re-exporting-loaders/'); await expect(page).toHaveTitle('Cookbook | Re-exporting loaders 📚 Qwik Documentation'); }); test('Qwik City HTML Attributes page loads', async ({ page }) => { await page.goto('/docs/html-attributes/'); await expect(page).toHaveTitle('HTML attributes | QwikCity 📚 Qwik Documentation'); }); test('Qwik City API Reference page loads', async ({ page }) => { await page.goto('/docs/api/'); await expect(page).toHaveTitle('API Reference | Qwik City 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/qwik-labs-pages-load.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('Qwik Labs Overview page loads', async ({ page }) => { await page.goto('/docs/labs/'); await expect(page).toHaveTitle('🧪 Qwik Labs | Overview 📚 Qwik Documentation'); }); test('Qwik Labs Insights page loads', async ({ page }) => { await page.goto('/docs/labs/insights/'); await expect(page).toHaveTitle('🧪 Insights | Qwik Labs 📚 Qwik Documentation'); }); test('Qwik Labs usePreventNavigate page loads', async ({ page }) => { await page.goto('/docs/labs/usePreventNavigate/'); await expect(page).toHaveTitle('🧪 usePreventNavigate | Qwik Labs 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/reference-pages-load.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('API Reference page loads', async ({ page }) => { await page.goto('/api/'); await expect(page).toHaveTitle('Qwik - Framework reimagined for the edge'); }); test('API Reference Deprecated Features page loads', async ({ page }) => { await page.goto('/docs/deprecated-features/'); await expect(page).toHaveTitle('Deprecated Features | Guides 📚 Qwik Documentation'); }); ================================================ FILE: e2e/docs-e2e/tests/Docs/searchBar.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('search bar with click results', async ({ page }) => { await page.goto('/'); await page.getByRole('button', { name: 'Search' }).click(); await page.getByPlaceholder('Search docs').fill('getting started qwikly'); await page.waitForSelector('.DocSearch-Hit', { timeout: 5000 }); const countOfSearchResults = await page.locator('.DocSearch-Hit').count(); expect(countOfSearchResults).toBeGreaterThan(0); await page.getByRole('link', { name: 'Getting Started Qwikly', exact: true }).click(); await expect(page).toHaveURL('docs/getting-started/#getting-started-qwikly'); }); test('search with no results', async ({ page }) => { await page.goto('/'); await page.getByRole('button', { name: 'Search' }).click(); await page.getByPlaceholder('Search docs').fill('xyz123nonexistentquery'); await page.waitForTimeout(1000); const noResults = page.locator('.DocSearch-NoResults, .DocSearch-EmptyState'); await expect(noResults).toBeVisible(); }); test('search bar opens and closes', async ({ page }) => { await page.goto('/'); await page.getByRole('button', { name: 'Search' }).click(); await expect(page.getByPlaceholder('Search docs')).toBeVisible(); await page.keyboard.press('Escape'); await expect(page.getByPlaceholder('Search docs')).not.toBeVisible(); }); ================================================ FILE: e2e/docs-e2e/tests/Ecosystem/ecosystem-pages-load.spec.ts ================================================ import { test, expect } from '@playwright/test'; test('Ecosystem page loads', async ({ page }) => { await page.goto('/ecosystem//'); await expect(page).toHaveTitle('Qwik Ecosystem 📚 Qwik Documentation'); }); test('Ecosystem Media Blogs Page loads', async ({ page }) => { await page.goto('/media/'); await expect(page).toHaveTitle( 'Qwik Presentations, Talks, Videos and Podcasts 📚 Qwik Documentation' ); }); ================================================ FILE: e2e/docs-e2e/tests/Sandbox/autoComplete.spec.ts ================================================ import { test, expect } from '@playwright/test'; test.describe('Sandbox Auto-complete Example', () => { test.beforeEach(async ({ page }) => { await page.goto('/examples/reactivity/auto-complete/'); }); test('Sandbox Auto-complete page loads', async ({ page }) => { await expect(page).toHaveTitle('Auto-complete 📚 Qwik Documentation'); const tabButtonsTop = page.getByText('app.tsxentry.server.tsxroot.'); await expect(tabButtonsTop.getByRole('button')).toHaveCount(3); await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); const consoleTabBottom = page.getByText('ConsoleOptions'); await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); }); test('Auto-complete app.tsx loads', async ({ page }) => { const replInputAppTsx = page .getByRole('code') .locator('div') .filter({ hasText: 'export default component$' }) .nth(4); await expect(replInputAppTsx).toBeVisible(); const serverEntryButton = page.getByRole('button', { name: 'entry.server.tsx' }); serverEntryButton.click(); await expect(replInputAppTsx).not.toBeVisible(); const appTsxButton = page.getByRole('button', { name: 'app.tsx' }); appTsxButton.click(); await expect(replInputAppTsx).toBeVisible(); }); test('Auto-complete entry.server.tsx loads', async ({ page }) => { const root = page .getByRole('code') .locator('div') .filter({ hasText: "import { Root } from './root';" }) .nth(4); await expect(root).not.toBeVisible(); const button = page.getByRole('button', { name: 'entry.server.tsx' }); button.click(); await expect(root).toBeVisible(); }); test('Auto-complete root.tsx loads', async ({ page }) => { const importStatement = page .getByRole('code') .locator('div') .filter({ hasText: "import App from './app';" }) .nth(4); await expect(importStatement).not.toBeVisible(); const button = page.getByRole('button', { name: 'root.tsx' }); await button.click(); await expect(importStatement).toBeVisible(); }); test('Auto-complete HTML Button', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const button = page.getByRole('button', { name: 'HTML' }); await button.click(); const htmlCode = page.locator('code.language-html'); await expect(htmlCode).toBeVisible(); await expect(htmlCode).toContainText(''); }); test('Auto-complete Symbols Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Symbols' }); await expect(button).toBeVisible(); await button.click(); const symbolsText = page.getByText('import { _jsxQ } from').first(); await expect(symbolsText).toBeVisible(); }); test('Auto-complete Client Bundles Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Client Bundles' }); await expect(button).toBeVisible(); await button.click(); const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); await expect(bundles).toBeVisible(); }); test('Auto-complete SSR Module Button', async ({ page }) => { const button = page.getByRole('button', { name: 'SSR Module' }); await expect(button).toBeVisible(); await button.click(); const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); await expect(module).toBeVisible(); }); test('Auto-complete Diagnostics Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Diagnostics' }); await expect(button).toBeVisible(); await button.click(); const diagnostics = page.locator('.output-result.output-diagnostics'); await expect(diagnostics).toBeVisible(); await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); }); test('Auto-complete Options Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Options' }); const serverConsoleText = page.getByText('🔴 Paused in server'); await expect(serverConsoleText).toBeVisible(); await expect(button).toBeVisible(); await button.click(); await expect(serverConsoleText).not.toBeVisible(); const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); await expect(DebugCheckBox).toBeVisible(); await expect(DebugCheckBox).not.toBeChecked(); const consoleButton = page.getByRole('button', { name: 'Console' }); consoleButton.click(); await expect(serverConsoleText).toBeVisible(); }); }); ================================================ FILE: e2e/docs-e2e/tests/Sandbox/clockVisible.spec.ts ================================================ import { test, expect } from '@playwright/test'; test.describe('Sandbox Clock Example', () => { test.beforeEach(async ({ page }) => { await page.goto('/examples/visibility/clock/'); }); test('Sandbox Clock page loads', async ({ page }) => { await expect(page).toHaveTitle('Below the fold Clock 📚 Qwik Documentation'); const tabButtonsTop = page.getByText('app.tsxclock.cssentry.server.'); await expect(tabButtonsTop.getByRole('button')).toHaveCount(4); await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'clock.css' })).toBeVisible(); await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); const consoleTabBottom = page.getByText('ConsoleOptions'); await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); }); test('Clock app.tsx loads', async ({ page }) => { const replInputAppTsx = page .getByRole('code') .locator('div') .filter({ hasText: 'export default component$' }) .nth(4); await expect(replInputAppTsx).toBeVisible(); const serverEntryButton = page.getByRole('button', { name: 'entry.server.tsx' }); serverEntryButton.click(); await expect(replInputAppTsx).not.toBeVisible(); const appTsxButton = page.getByRole('button', { name: 'app.tsx' }); appTsxButton.click(); await expect(replInputAppTsx).toBeVisible(); }); test('Clock Clock.css loads', async ({ page }) => { const clockCSS = page.getByText('background: #fff;'); const button = page.getByRole('button', { name: 'clock.css' }); await expect(clockCSS).not.toBeVisible(); button.click(); await expect(clockCSS).toBeVisible(); }); test('Clock entry.server.tsx loads', async ({ page }) => { const root = page .getByRole('code') .locator('div') .filter({ hasText: "import { Root } from './root';" }) .nth(4); await expect(root).not.toBeVisible(); const button = page.getByRole('button', { name: 'entry.server.tsx' }); button.click(); await expect(root).toBeVisible(); }); test('Clock root.tsx loads', async ({ page }) => { const importStatement = page .getByRole('code') .locator('div') .filter({ hasText: "import App from './app';" }) .nth(4); await expect(importStatement).not.toBeVisible(); const button = page.getByRole('button', { name: 'root.tsx' }); await button.click(); await expect(importStatement).toBeVisible(); }); test('Clock HTML Button', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const button = page.getByRole('button', { name: 'HTML' }); await button.click(); const htmlCode = page.locator('code.language-html'); await expect(htmlCode).toBeVisible(); await expect(htmlCode).toContainText(''); }); test('Clock Symbols Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Symbols' }); await expect(button).toBeVisible(); await button.click(); const symbolsText = page.getByText('import { _jsxQ } from').first(); await expect(symbolsText).toBeVisible(); }); test('Clock Client Bundles Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Client Bundles' }); await expect(button).toBeVisible(); await button.click(); const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); await expect(bundles).toBeVisible(); }); test('Clock SSR Module Button', async ({ page }) => { const button = page.getByRole('button', { name: 'SSR Module' }); await expect(button).toBeVisible(); await button.click(); const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); await expect(module).toBeVisible(); }); test('Clock Diagnostics Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Diagnostics' }); await expect(button).toBeVisible(); await button.click(); const diagnostics = page.locator('.output-result.output-diagnostics'); await expect(diagnostics).toBeVisible(); await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); }); test('Clock Options Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Options' }); const serverConsoleText = page.getByText('🔴 Paused in server'); await expect(serverConsoleText).toBeVisible(); await expect(button).toBeVisible(); await button.click(); await expect(serverConsoleText).not.toBeVisible(); const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); await expect(DebugCheckBox).toBeVisible(); await expect(DebugCheckBox).not.toBeChecked(); const consoleButton = page.getByRole('button', { name: 'Console' }); consoleButton.click(); await expect(serverConsoleText).toBeVisible(); }); test('Clock Visible Task ', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const resumed = page.getByText('🟢 Resumed in client'); await expect(resumed).not.toBeVisible(); const outerFrame = await page.locator('iframe').elementHandle(); const outerFrameContent = await outerFrame?.contentFrame(); const innerFrameHandle = await outerFrameContent?.locator('iframe').elementHandle(); const innerFrame = await innerFrameHandle?.contentFrame(); await innerFrame?.evaluate(() => { window.scrollTo(0, document.body.scrollHeight); }); await expect(resumed).toBeVisible(); }); }); ================================================ FILE: e2e/docs-e2e/tests/Sandbox/counter.spec.ts ================================================ import { test, expect } from '@playwright/test'; test.describe('Sandbox Counter Example', () => { test.beforeEach(async ({ page }) => { await page.goto('/examples/reactivity/counter/'); }); test('Sandbox Counter page loads', async ({ page }) => { await expect(page).toHaveTitle('Counter 📚 Qwik Documentation'); const tabButtonsTop = page.getByText('app.tsxentry.server.tsxroot.'); await expect(tabButtonsTop.getByRole('button')).toHaveCount(3); await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); const consoleTabBottom = page.getByText('ConsoleOptions'); await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); }); test('Counter app.tsx loads', async ({ page }) => { const replInputAppTsx = page .getByRole('code') .locator('div') .filter({ hasText: 'export default component$' }) .nth(4); await expect(replInputAppTsx).toBeVisible(); const serverEntryButton = page.getByRole('button', { name: 'entry.server.tsx' }); serverEntryButton.click(); await expect(replInputAppTsx).not.toBeVisible(); const appTsxButton = page.getByRole('button', { name: 'app.tsx' }); appTsxButton.click(); await expect(replInputAppTsx).toBeVisible(); }); test('Counter entry.server.tsx loads', async ({ page }) => { const root = page .getByRole('code') .locator('div') .filter({ hasText: "import { Root } from './root';" }) .nth(4); await expect(root).not.toBeVisible(); const button = page.getByRole('button', { name: 'entry.server.tsx' }); button.click(); await expect(root).toBeVisible(); }); test('Counter root.tsx loads', async ({ page }) => { const importStatement = page .getByRole('code') .locator('div') .filter({ hasText: "import App from './app';" }) .nth(4); await expect(importStatement).not.toBeVisible(); const button = page.getByRole('button', { name: 'root.tsx' }); await button.click(); await expect(importStatement).toBeVisible(); }); test('Counter Click Button', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const countValue = page .locator('iframe') .contentFrame() .locator('iframe') .contentFrame() .locator('main>p') .first(); const button = page .locator('iframe') .contentFrame() .locator('iframe') .contentFrame() .getByRole('button', { name: 'Click' }); const resumed = page.getByText('🟢 Resumed in client'); await expect(resumed).not.toBeVisible(); await expect(countValue).toHaveText('Count: 0'); await button.click(); await expect(countValue).toHaveText('Count: 1'); await expect(resumed).toBeVisible(); }); test('Counter HTML Button', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const button = page.getByRole('button', { name: 'HTML' }); await button.click(); const htmlCode = page.locator('code.language-html'); await expect(htmlCode).toBeVisible(); await expect(htmlCode).toContainText(''); }); test('Counter Symbols Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Symbols' }); await expect(button).toBeVisible(); await button.click(); const symbolsText = page.getByText('import { _jsxQ } from'); await expect(symbolsText).toBeVisible(); }); test('Counter Client Bundles Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Client Bundles' }); await expect(button).toBeVisible(); await button.click(); const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); await expect(bundles).toBeVisible(); }); test('Counter SSR Module Button', async ({ page }) => { const button = page.getByRole('button', { name: 'SSR Module' }); await expect(button).toBeVisible(); await button.click(); const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); await expect(module).toBeVisible(); }); test('Counter Diagnostics Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Diagnostics' }); await expect(button).toBeVisible(); await button.click(); const diagnostics = page.locator('.output-result.output-diagnostics'); await expect(diagnostics).toBeVisible(); await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); }); test('Counter Options Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Options' }); const serverConsoleText = page.getByText('🔴 Paused in server'); await expect(serverConsoleText).toBeVisible(); await expect(button).toBeVisible(); await button.click(); await expect(serverConsoleText).not.toBeVisible(); const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); await expect(DebugCheckBox).toBeVisible(); await expect(DebugCheckBox).not.toBeChecked(); const consoleButton = page.getByRole('button', { name: 'Console' }); consoleButton.click(); await expect(serverConsoleText).toBeVisible(); }); }); ================================================ FILE: e2e/docs-e2e/tests/Sandbox/partial.spec.ts ================================================ import { test, expect } from '@playwright/test'; test.describe('Sandbox Partials HackerNews Example', () => { test.beforeEach(async ({ page }) => { await page.goto('/examples/partial/hackernews-index/'); }); test('Partial HackerNews page loads', async ({ page }) => { await expect(page).toHaveTitle('HackerNews 📚 Qwik Documentation'); const tabButtonsTop = page.getByText('app.tsxentry.server.tsxhacker'); await expect(tabButtonsTop.getByRole('button')).toHaveCount(4); await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'hacker-news.css' })).toBeVisible(); await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); const consoleTabBottom = page.getByText('ConsoleOptions'); await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); }); test('Partial HackerNews app.tsx loads', async ({ page }) => { const replInputAppTsx = page .getByRole('code') .getByText('export const HackerNews = component$'); await expect(replInputAppTsx).toBeVisible(); const serverEntryButton = page.getByRole('button', { name: 'entry.server.tsx' }); serverEntryButton.click(); await expect(replInputAppTsx).not.toBeVisible(); const appTsxButton = page.getByRole('button', { name: 'app.tsx' }); appTsxButton.click(); await expect(replInputAppTsx).toBeVisible(); }); test('Partial HackerNews entry.server.tsx loads', async ({ page }) => { const root = page .getByRole('code') .locator('div') .filter({ hasText: "import { Root } from './root';" }) .nth(4); await expect(root).not.toBeVisible(); const button = page.getByRole('button', { name: 'entry.server.tsx' }); button.click(); await expect(root).toBeVisible(); }); test('Partial HackerNews root.tsx loads', async ({ page }) => { const importStatement = page .getByRole('code') .locator('div') .filter({ hasText: "import { HackerNews } from './app';" }) .nth(4); await expect(importStatement).not.toBeVisible(); const button = page.getByRole('button', { name: 'root.tsx' }); await button.click(); await expect(importStatement).toBeVisible(); }); test('Partial HackerNews hacker-news.css loads', async ({ page }) => { const clockCSS = page.getByText('background-color: #f2f3f5;'); const button = page.getByRole('button', { name: 'hacker-news.css' }); await expect(clockCSS).not.toBeVisible(); button.click(); await expect(clockCSS).toBeVisible(); }); test('Partial HackerNews fetchRequest Loads', async ({ page }) => { const linkToNextPage = page .locator('iframe') .contentFrame() .locator('iframe') .contentFrame() .getByRole('link', { name: 'Next Page' }); const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); await expect(linkToNextPage).toBeVisible(); }); test('Partial HackerNews HTML Button', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const button = page.getByRole('button', { name: 'HTML' }); await button.click(); const htmlCode = page.locator('code.language-html'); await expect(htmlCode).toBeVisible(); await expect(htmlCode).toContainText(''); }); test('Partial HackerNews Symbols Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Symbols' }); await expect(button).toBeVisible(); await button.click(); const symbolsText = page.getByText('import { _jsxQ } from').first(); await expect(symbolsText).toBeVisible(); }); test('Partial HackerNews Client Bundles Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Client Bundles' }); await expect(button).toBeVisible(); await button.click(); const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); await expect(bundles).toBeVisible(); }); test('Partial HackerNews SSR Module Button', async ({ page }) => { const button = page.getByRole('button', { name: 'SSR Module' }); await expect(button).toBeVisible(); await button.click(); const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); await expect(module).toBeVisible(); }); test('Partial HackerNews Diagnostics Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Diagnostics' }); await expect(button).toBeVisible(); await button.click(); const diagnostics = page.locator('.output-result.output-diagnostics'); await expect(diagnostics).toBeVisible(); await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); }); test('Clock Options Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Options' }); const serverConsoleText = page.getByText('🔴 Paused in server'); await expect(serverConsoleText).toBeVisible(); await expect(button).toBeVisible(); await button.click(); await expect(serverConsoleText).not.toBeVisible(); const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); await expect(DebugCheckBox).toBeVisible(); await expect(DebugCheckBox).not.toBeChecked(); const consoleButton = page.getByRole('button', { name: 'Console' }); consoleButton.click(); await expect(serverConsoleText).toBeVisible(); }); }); ================================================ FILE: e2e/docs-e2e/tests/Sandbox/routing.spec.ts ================================================ import { test, expect } from '@playwright/test'; test.describe('Sandbox Routing ', () => { test.beforeEach(async ({ page }) => { await page.goto('/examples/introduction/hello-world/'); const Links = page.locator('.examples-menu a'); const linkCount = await Links.count(); expect(linkCount).toBe(8); }); test.afterEach(async ({ page }) => { const link = page.getByRole('link', { name: '🌎 Hello World The simplest' }); await expect(link).toBeVisible(); await link.click(); await expect(page).toHaveTitle('Hello World - Qwik'); }); test('Routing runtime-less link test', async ({ page }) => { const link = page.getByRole('link', { name: '🪶 Runtime-less' }); await expect(link).toBeVisible(); await link.click(); await page.waitForLoadState('networkidle'); expect(page.url()).toContain('/examples/introduction/runtime-less'); }); test('Routing useTask() link test', async ({ page }) => { const link = page.getByRole('link', { name: '👀 Simple useTask()' }); await expect(link).toBeVisible(); await link.click(); await page.waitForLoadState('networkidle'); expect(page.url()).toContain('/examples/reactivity/task/'); }); test('Routing Counter link test', async ({ page }) => { const link = page.getByRole('link', { name: '⏲ Counter' }); await expect(link).toBeVisible(); await link.click(); await page.waitForLoadState('networkidle'); expect(page.url()).toContain('/examples/reactivity/counter/'); }); test('Routing Auto Complete link test', async ({ page }) => { const link = page.getByRole('link', { name: '🎬 Auto-complete' }); await expect(link).toBeVisible(); await link.click(); await page.waitForLoadState('networkidle'); expect(page.url()).toContain('/examples/reactivity/auto-complete/'); }); test('Routing Below the fold Clock link test', async ({ page }) => { const link = page.getByRole('link', { name: '⏰ Below the fold Clock' }); await expect(link).toBeVisible(); await link.click(); await page.waitForLoadState('networkidle'); expect(page.url()).toContain('/examples/visibility/clock/'); }); test('Routing Partials HN link test', async ({ page }) => { const link = page.getByRole('link', { name: '📰 HackerNews HackerNews' }); await expect(link).toBeVisible(); await link.click(); await page.waitForLoadState('networkidle'); expect(page.url()).toContain('/examples/partial/hackernews-index/'); }); }); ================================================ FILE: e2e/docs-e2e/tests/Sandbox/sandbox.spec.ts ================================================ import { test, expect } from '@playwright/test'; test.describe('Sandbox Hello World Example', () => { test.beforeEach(async ({ page }) => { await page.goto('/examples/introduction/hello-world/'); }); test('Sandbox page loads', async ({ page }) => { await expect(page).toHaveTitle('Hello World 📚 Qwik Documentation'); const tabButtonsTop = page.getByText('app.tsxentry.server.tsxroot.'); await expect(tabButtonsTop.getByRole('button')).toHaveCount(3); await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); const consoleTabBottom = page.getByText('ConsoleOptions'); await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); }); test('Hello world app loads', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const appText = page .getByRole('main') .locator('iframe') .contentFrame() .locator('iframe') .contentFrame() .getByText('Hello Qwik'); await expect(appText).toBeVisible(); }); test('Hello World app.tsx loads', async ({ page }) => { const text = page .getByRole('code') .locator('div') .filter({ hasText: 'return

Hello Qwik

;' }) .nth(4); await expect(text).toBeVisible(); }); test('Hello World update p tag', async ({ page }) => { const text = page .getByRole('code') .locator('div') .filter({ hasText: 'return

Hello Qwik

;' }) .nth(4); await expect(text).toBeVisible(); await text.click(); await page.keyboard.press('Home'); await page.keyboard.press('Shift+End'); await page.keyboard.type('return

Hello Test 1234

;'); await expect(text).not.toBeVisible(); const appText = page .getByRole('main') .locator('iframe') .first() .contentFrame() .locator('iframe') .first() .contentFrame() .getByText('Hello Test 1234'); await expect(appText).toBeVisible(); }); test('Hello World entry.server.tsx tab works', async ({ page }) => { const button = page.getByRole('button', { name: 'entry.server.tsx' }); await expect(button).toBeVisible(); await button.click(); const root = page .getByRole('code') .locator('div') .filter({ hasText: "import { Root } from './root';" }) .nth(4); await expect(root).toBeVisible(); }); test('Hello World root.tsx tab works', async ({ page }) => { const button = page.getByRole('button', { name: 'root.tsx' }); await expect(button).toBeVisible(); await button.click(); const app = page .getByRole('code') .locator('div') .filter({ hasText: "import App from './app';" }) .nth(4); await expect(app).toBeVisible(); }); test('Hello world HTML Button', async ({ page }) => { const htmlButton = page.getByRole('button', { name: 'HTML' }); await expect(htmlButton).toBeVisible(); await htmlButton.click(); const htmlCode = page.locator('code.language-html'); await expect(htmlCode).toBeVisible(); await expect(htmlCode).toContainText(''); }); test('Hello world Symbols Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Symbols' }); await expect(button).toBeVisible(); await button.click(); const symbolsText = page.getByText('import { _jsxQ } from'); await expect(symbolsText).toBeVisible(); }); test('Hello world Client Bundles Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Client Bundles' }); await expect(button).toBeVisible(); await button.click(); const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); await expect(bundles).toBeVisible(); }); test('Hello world SSR Module Button', async ({ page }) => { const button = page.getByRole('button', { name: 'SSR Module' }); await expect(button).toBeVisible(); await button.click(); const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); await expect(module).toBeVisible(); }); test('Hello world Diagnostics Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Diagnostics' }); await expect(button).toBeVisible(); await button.click(); const diagnostics = page.locator('.output-result.output-diagnostics'); await expect(diagnostics).toBeVisible(); await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); }); test('Hello world Console', async ({ page }) => { const button = page.getByRole('button', { name: 'Console' }); await expect(button).toBeVisible(); const serverConsoleText = page.getByText('🔴 Paused in server'); await expect(serverConsoleText).toBeVisible(); }); test('Hello world Options Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Options' }); await expect(button).toBeVisible(); await button.click(); const serverConsoleText = page.getByText('🔴 Paused in server'); await expect(serverConsoleText).not.toBeVisible(); const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); await expect(DebugCheckBox).toBeVisible(); await expect(DebugCheckBox).not.toBeChecked(); }); }); test.describe('Sandbox Runtime-less Example', () => { test.beforeEach(async ({ page }) => { await page.goto('/examples/introduction/runtime-less/'); }); test('Sandbox Runtime-less page loads', async ({ page }) => { await expect(page).toHaveTitle('Runtime-less 📚 Qwik Documentation'); const tabButtonsTop = page.getByText('app.tsxentry.server.tsxroot.'); await expect(tabButtonsTop.getByRole('button')).toHaveCount(3); await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); const consoleTabBottom = page.getByText('ConsoleOptions'); await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); const consoleLogSSR = page.getByText('ssr render '); await expect(consoleLogSSR).toHaveCount(1); await expect(consoleLogSSR).toBeVisible(); }); test('Runtime-less APP.tsx loads', async ({ page }) => { const replInputAppTsx = page .getByRole('code') .locator('div') .filter({ hasText: "console.log('render ');" }) .nth(4); await expect(replInputAppTsx).toBeVisible(); const serverEntryButton = page.getByRole('button', { name: 'entry.server.tsx' }); serverEntryButton.click(); await expect(replInputAppTsx).not.toBeVisible(); const appTsxButton = page.getByRole('button', { name: 'app.tsx' }); appTsxButton.click(); await expect(replInputAppTsx).toBeVisible(); }); test('Runtime-less entry.server.tsx loads', async ({ page }) => { const root = page .getByRole('code') .locator('div') .filter({ hasText: "import { Root } from './root';" }) .nth(4); await expect(root).not.toBeVisible(); const button = page.getByRole('button', { name: 'entry.server.tsx' }); button.click(); await expect(root).toBeVisible(); }); test('Runtime-less root.tsx loads', async ({ page }) => { const importStatement = page .getByRole('code') .locator('div') .filter({ hasText: "import App from './app';" }) .nth(4); await expect(importStatement).not.toBeVisible(); const button = page.getByRole('button', { name: 'root.tsx' }); await button.click(); await expect(importStatement).toBeVisible(); }); test('Runtime-less Action Button', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const button = page .locator('iframe') .contentFrame() .locator('iframe') .contentFrame() .getByRole('button', { name: 'Action' }); await button.click(); const clicked = page.getByText('client click'); await expect(clicked).toHaveCount(1); await button.click(); await expect(clicked).toHaveCount(2); }); test('Runtime-less HTML Button', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const button = page.getByRole('button', { name: 'HTML' }); await button.click(); const htmlCode = page.locator('code.language-html'); await expect(htmlCode).toBeVisible(); await expect(htmlCode).toContainText(''); }); test('Runtime-less Symbols Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Symbols' }); await expect(button).toBeVisible(); await button.click(); const symbolsText = page.getByText('import { _jsxQ } from'); await expect(symbolsText).toBeVisible(); }); test('Runtime-less Client Bundles Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Client Bundles' }); await expect(button).toBeVisible(); await button.click(); const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); await expect(bundles).toBeVisible(); }); test('Runtime-less SSR Module Button', async ({ page }) => { const button = page.getByRole('button', { name: 'SSR Module' }); await expect(button).toBeVisible(); await button.click(); const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); await expect(module).toBeVisible(); }); test('Runtime-less Diagnostics Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Diagnostics' }); await expect(button).toBeVisible(); await button.click(); const diagnostics = page.locator('.output-result.output-diagnostics'); await expect(diagnostics).toBeVisible(); await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); }); test('Runtime-less Options Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Options' }); const serverConsoleText = page.getByText('🔴 Paused in server'); await expect(serverConsoleText).toBeVisible(); await expect(button).toBeVisible(); await button.click(); await expect(serverConsoleText).not.toBeVisible(); const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); await expect(DebugCheckBox).toBeVisible(); await expect(DebugCheckBox).not.toBeChecked(); const consoleButton = page.getByRole('button', { name: 'Console' }); consoleButton.click(); await expect(serverConsoleText).toBeVisible(); }); }); ================================================ FILE: e2e/docs-e2e/tests/Sandbox/usetask.spec.ts ================================================ import { test, expect } from '@playwright/test'; test.describe('Sandbox useTask', () => { test.beforeEach(async ({ page }) => { await page.goto('/examples/reactivity/task/'); }); test('useTask page loads', async ({ page }) => { await expect(page).toHaveTitle('Simple useTask() 📚 Qwik Documentation'); const tabButtonsTop = page.getByText('app.tsxentry.server.tsxroot.'); await expect(tabButtonsTop.getByRole('button')).toHaveCount(3); await expect(page.getByRole('button', { name: 'app.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'entry.server.tsx' })).toBeVisible(); await expect(page.getByRole('button', { name: 'root.tsx' })).toBeVisible(); const tabButtonsBottom = page.getByText('AppHTMLSymbolsClient'); await expect(tabButtonsBottom.getByRole('button')).toHaveCount(6); await expect(tabButtonsBottom.getByRole('button', { name: 'App' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'HTML' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Symbols' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Client Bundles' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'SSR Module' })).toBeVisible(); await expect(tabButtonsBottom.getByRole('button', { name: 'Diagnostics' })).toBeVisible(); const consoleTabBottom = page.getByText('ConsoleOptions'); await expect(consoleTabBottom.getByRole('button')).toHaveCount(2); await expect(consoleTabBottom.getByRole('button', { name: 'Console' })).toBeVisible(); await expect(consoleTabBottom.getByRole('button', { name: 'Options' })).toBeVisible(); }); test('useTask app.tsx loads', async ({ page }) => { const appTsxButton = page.getByRole('button', { name: 'app.tsx' }); const replInputAppTsx = page .getByRole('code') .locator('div') .filter({ hasText: 'export default component$' }) .nth(4); await expect(replInputAppTsx).toBeVisible(); const serverEntryButton = page.getByRole('button', { name: 'entry.server.tsx' }); serverEntryButton.click(); await expect(replInputAppTsx).not.toBeVisible(); appTsxButton.click(); await expect(replInputAppTsx).toBeVisible(); }); test('useTask entry.server.tsx loads', async ({ page }) => { const root = page .getByRole('code') .locator('div') .filter({ hasText: "import { Root } from './root';" }) .nth(4); await expect(root).not.toBeVisible(); const button = page.getByRole('button', { name: 'entry.server.tsx' }); button.click(); await expect(root).toBeVisible(); }); test('useTask root.tsx loads', async ({ page }) => { const importStatement = page .getByRole('code') .locator('div') .filter({ hasText: "import App from './app';" }) .nth(4); await expect(importStatement).not.toBeVisible(); const button = page.getByRole('button', { name: 'root.tsx' }); await button.click(); await expect(importStatement).toBeVisible(); }); test('useTask Debounced Button', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const button = page .locator('iframe') .contentFrame() .locator('iframe') .contentFrame() .getByRole('button', { name: '+' }); const childValue = page .locator('iframe') .contentFrame() .locator('iframe') .contentFrame() .locator('#child'); const consoleUpdate = page.getByText('client count changed'); const resumed = page.getByText('🟢 Resumed in client'); const debouncedSelector = page .locator('iframe') .contentFrame() .locator('iframe') .contentFrame() .locator('#debounced'); await expect(debouncedSelector).toHaveText('Debounced: 0'); await expect(childValue).toHaveText('0'); await expect(resumed).not.toBeVisible(); await expect(consoleUpdate).not.toBeVisible(); button.click(); await expect(consoleUpdate).toHaveCount(1); await expect(consoleUpdate).toBeVisible(); await expect(resumed).toBeVisible(); await expect(debouncedSelector).toHaveText('Debounced: 1'); await expect(childValue).toHaveText('1'); }); test('useTask HTML Button', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const button = page.getByRole('button', { name: 'HTML' }); await button.click(); const htmlCode = page.locator('code.language-html'); await expect(htmlCode).toBeVisible(); await expect(htmlCode).toContainText(''); }); test('useTask Symbols Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Symbols' }); await expect(button).toBeVisible(); await button.click(); const symbolsText = page.getByText('import { useLexicalScope } ').first(); await expect(symbolsText).toBeVisible(); }); test('useTask Client Bundles Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Client Bundles' }); await expect(button).toBeVisible(); await button.click(); const bundles = page.locator('#file-modules-client-modules').getByText('build/app.js'); await expect(bundles).toBeVisible(); }); test('useTask SSR Module Button', async ({ page }) => { const button = page.getByRole('button', { name: 'SSR Module' }); await expect(button).toBeVisible(); await button.click(); const module = page.locator('#file-modules-client-modules').getByText('entry.server.js'); await expect(module).toBeVisible(); }); test('useTask Diagnostics Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Diagnostics' }); await expect(button).toBeVisible(); await button.click(); const diagnostics = page.locator('.output-result.output-diagnostics'); await expect(diagnostics).toBeVisible(); await expect(diagnostics).toHaveText('- No Reported Diagnostics -'); }); test('useTask Options Button', async ({ page }) => { const button = page.getByRole('button', { name: 'Options' }); const serverConsoleText = page.getByText('🔴 Paused in server'); await expect(serverConsoleText).toBeVisible(); await expect(button).toBeVisible(); await button.click(); await expect(serverConsoleText).not.toBeVisible(); const DebugCheckBox = page.locator('label').filter({ hasText: 'Debug' }); await expect(DebugCheckBox).toBeVisible(); await expect(DebugCheckBox).not.toBeChecked(); const consoleButton = page.getByRole('button', { name: 'Console' }); consoleButton.click(); await expect(serverConsoleText).toBeVisible(); }); test('useTask server console loads', async ({ page }) => { const spinner = page.locator('.repl-spinner'); await expect(spinner).toBeVisible(); await expect(spinner).not.toBeVisible(); const ssrPageCount = page.getByText('ssr count changed'); const ssrAppRenders = page.getByText('ssr renders'); const ssrChildRenders = page.getByText('ssr render'); const ssrGrandChildRenders = page.getByText('ssr render'); const pausedInServer = page.getByText('🔴 Paused in server'); await expect(ssrPageCount).toBeVisible(); await expect(ssrAppRenders).toBeVisible(); await expect(ssrChildRenders).toBeVisible(); await expect(ssrGrandChildRenders).toBeVisible(); await expect(pausedInServer).toBeVisible(); }); }); ================================================ FILE: e2e/qwik-cli-e2e/README.md ================================================ # CLI E2E tests for the Qwik Framework This package provides isolated E2E tests by generating a new application with local packages and then running tests again that code by executing it and verifying expected behavior. ## Description Tests can be invoked by running `pnpm run test.e2e.cli`. **Note that running E2E tests requires the workspace projects to be prebuilt manually!** E2E project does the following internally: 0. Vitest is configured to run a setup function once **PRIOR TO ALL** tests. During the setup `@builder.io/qwik`, `@builder.io/qwik-city` and `eslint-plugin-qwik` packages will be packed with `pnpm pack` Those will be used at a step 2 for every test. Tarballs are located in `temp/tarballs` folder within this repo. It is assumed that packages are built before E2E is executed. 1. Simulates `npm create qwik` locally using direct command `node packages/create-qwik/create-qwik.cjs playground {outputDir}` - By default `outputDir` is an auto-generated one using `tmp` npm package. The application that is created here will be removed after the test is executed - It is possible to install into custom folder using environment variable `TEMP_E2E_PATH`. Here's how the command would look like in this case: - with absolute path `TEMP_E2E_PATH=/Users/name/projects/tests pnpm run test.e2e.cli` - with path relative to the qwik workspace `TEMP_E2E_PATH=temp/e2e-folder pnpm run test.e2e.cli` Note that provided folder should exist. If custom path is used, generated application will not be removed after the test completes, which is helpful for debugging. 2. Uses packed `@builder.io/qwik`, `@builder.io/qwik-city` and `eslint-plugin-qwik` packages to update package.json file of the generated application with `file:path-to-package.tgz`. 3. Runs actual tests. Please pay attention at the `beforeAll` hook in the spec file ```typescript beforeAll(() => { const config = scaffoldQwikProject(); global.tmpDir = config.tmpDir; return async () => { await killAllRegisteredProcesses(); config.cleanupFn(); }; }); ``` Notice that `beforeAll` returns a function, which will be executed after the test completes either with success or failure. Both `config.cleanupFn();` and `killAllRegisteredProcesses` there are extremely important: - `config.cleanupFn()` is used in order to remove temporary folder with generated project after the test is executed (again, it's not being removed if `TEMP_E2E_PATH` is provided). - `killAllRegisteredProcesses` should be used to remove any active ports as we are serving the app during the test execution. Processes are being registered internally when `runCommandUntil` is executed. If you're executing something manually, you can use `registerExecutedChildProcess` utility to register the process. Despite `killAllRegisteredProcesses` will kill all processes when test exists, it is also a good practice to kill the process manually within the `it` statement using `await promisifiedTreeKill(yourChildProcess.pId, 'SIGKILL')` ## Adding new tests Right now we have only one test file within this project. This means only one test application will be created and used, which is good from the execution time standpoint. If more files are added, it shouldn't potentially be a problem as we have `fileParallelism: false` set in the `vite.config.ts`, which means only one test will be executed at a time. This obviously slows down the execution time, but is safer, because we're working with a real file system. ================================================ FILE: e2e/qwik-cli-e2e/package.json ================================================ { "name": "qwik-cli-e2e", "version": "0.0.0", "dependencies": { "kleur": "4.1.5" }, "private": true, "scripts": { "e2e": "vitest run --config=vite.config.ts", "e2e.watch": "vitest watch --config=vite.config.ts" } } ================================================ FILE: e2e/qwik-cli-e2e/tests/serve.spec.ts ================================================ /* eslint-disable no-console */ import { existsSync, readFileSync, writeFileSync } from 'fs'; import { join } from 'path'; import { assert, beforeAll, beforeEach, describe, expect, test } from 'vitest'; import { assertHostUnused, DEFAULT_TIMEOUT, getPageHtml, killAllRegisteredProcesses, log, promisifiedTreeKill, runCommandUntil, scaffoldQwikProject, type QwikProjectType, } from '../utils'; let SERVE_PORT = 3535; beforeEach(() => { // the port doesn't clear immediately after the previous test SERVE_PORT++; }); for (const type of ['empty', 'playground'] as QwikProjectType[]) { describe(`template: ${type}`, () => { beforeAll(() => { console.log('================================================ scaffolding', type); const config = scaffoldQwikProject(type); global.tmpDir = config.tmpDir; return async () => { try { await killAllRegisteredProcesses(); } catch (e) { log(`Error during process cleanup: ${e.message}`); } config.cleanupFn(); }; }); if (type === 'playground') { test( 'Should serve the app in dev mode and update the content on hot reload', { timeout: DEFAULT_TIMEOUT }, async () => { const host = `http://localhost:${SERVE_PORT}/`; await assertHostUnused(host); const p = await runCommandUntil( `npm run dev -- --port ${SERVE_PORT}`, global.tmpDir, (output) => { return output.includes(host); } ); assert.equal(existsSync(global.tmpDir), true); await expectHtmlOnARootPage(host); // Don't let process termination errors fail the test try { await promisifiedTreeKill(p.pid!, 'SIGKILL'); } catch (e) { log(`Error terminating dev server: ${e.message}`); } } ); } test('Should preview the app', { timeout: DEFAULT_TIMEOUT }, async () => { const host = `http://localhost:${SERVE_PORT}/`; await assertHostUnused(host); // First build the app const buildProcess = await runCommandUntil(`npm run build`, global.tmpDir, (output) => { return output.includes('dist/build') || output.includes('built in'); }); try { await promisifiedTreeKill(buildProcess.pid!, 'SIGKILL'); } catch (e) { log(`Error terminating build process: ${e.message}`); } // Now run the preview const p = await runCommandUntil( `npm run preview -- --no-open --port ${SERVE_PORT}`, global.tmpDir, (output) => { return output.includes(host); } ); assert.equal(existsSync(global.tmpDir), true); // Wait a bit for the server to fully start await new Promise((resolve) => setTimeout(resolve, 2000)); const res = await fetch(host, { headers: { accept: 'text/html' } }).then((r) => r.text()); console.log('** res', res); // Check for the appropriate content based on template type if (type === 'playground') { expect(res).toContain('fantastic'); } else if (type === 'empty') { expect(res).toContain('Hi'); expect(res).toContain('qwik'); } try { await promisifiedTreeKill(p.pid!, 'SIGKILL'); } catch (e) { log(`Error terminating preview server: ${e.message}`); } }); }); } async function expectHtmlOnARootPage(host: string) { expect((await getPageHtml(host)).querySelector('.container h1')?.textContent).toBe( `So fantasticto have you here` ); const heroComponentPath = join(global.tmpDir, `src/components/starter/hero/hero.tsx`); const heroComponentTextContent = readFileSync(heroComponentPath, 'utf-8'); writeFileSync( heroComponentPath, heroComponentTextContent.replace( `to have you here`, `to have e2e tests here` ) ); // wait for the arbitrary amount of time before the app is reloaded await new Promise((r) => setTimeout(r, 2000)); expect((await getPageHtml(host)).querySelector('.container h1')?.textContent).toBe( `So fantasticto have e2e tests here` ); } ================================================ FILE: e2e/qwik-cli-e2e/tsconfig.json ================================================ { "compilerOptions": { "types": ["vitest/globals"], "esModuleInterop": true }, "include": ["utils", "tests"] } ================================================ FILE: e2e/qwik-cli-e2e/utils/index.ts ================================================ import { ChildProcess, exec, execSync } from 'child_process'; import { existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs'; import { yellow } from 'kleur/colors'; import { dirname, join, resolve } from 'path'; import { dirSync } from 'tmp'; import treeKill from 'tree-kill'; import { promisify } from 'util'; import { createDocument } from '../../../packages/qwik/src/testing/document'; export type QwikProjectType = 'playground' | 'library' | 'empty'; export function scaffoldQwikProject(type: QwikProjectType): { tmpDir: string; cleanupFn: () => void; } { const tmpHostDirData = getTmpDirSync( process.env.TEMP_E2E_PATH ? `${process.env.TEMP_E2E_PATH}/${type}` : undefined ); const cleanupFn = () => { if (!tmpHostDirData.overridden) { cleanup(tmpHostDirData.path); } else { log('Custom E2E test path was used, skipping the removal of test folder'); } }; try { const tmpDir = runCreateQwikCommand(tmpHostDirData.path, type); log(`Created test application at "${tmpDir}"`); replacePackagesWithLocalOnes(tmpDir); return { cleanupFn, tmpDir }; } catch (error) { cleanupFn(); throw error; } } function cleanup(tmpDir: string) { log(`Removing tmp dir "${tmpDir}"`); rmSync(tmpDir, { recursive: true }); } function getTmpDirSync(tmpDirOverride?: string) { if (tmpDirOverride) { tmpDirOverride = resolve(workspaceRoot, tmpDirOverride); } if (tmpDirOverride && !existsSync(tmpDirOverride)) { throw new Error(`"${tmpDirOverride}" does not exist.`); } if (tmpDirOverride) { const p = join(tmpDirOverride, 'qwik_e2e'); if (existsSync(p)) { log(`Removing project folder "${p}" (will be recreated).`); rmSync(p, { recursive: true }); } mkdirSync(p); return { path: p, overridden: true }; } return { path: dirSync({ prefix: 'qwik_e2e' }).name, overridden: false }; } function runCreateQwikCommand(tmpDir: string, type: 'playground' | 'library' | 'empty'): string { const appDir = 'e2e-app'; execSync( `node "${workspaceRoot}/packages/create-qwik/create-qwik.cjs" ${type} "${join(tmpDir, appDir)}"` ); return join(tmpDir, appDir); } function replacePackagesWithLocalOnes(tmpDir: string) { const tarballConfig = JSON.parse( readFileSync(join(workspaceRoot, 'temp/tarballs/paths.json'), 'utf-8') ); for (const { name, absolutePath } of tarballConfig) { patchPackageJsonForPlugin(tmpDir, name, absolutePath); } execSync('pnpm i', { cwd: tmpDir, // only output errors stdio: ['ignore', 'inherit', 'inherit'], }); } function patchPackageJsonForPlugin(tmpDirName: string, npmPackageName: string, distPath: string) { const path = join(tmpDirName, 'package.json'); const json = JSON.parse(readFileSync(path, 'utf-8')); json.devDependencies[npmPackageName] = `file:${distPath}`; writeFileSync(path, JSON.stringify(json)); } export function registerExecutedChildProcess(process: ChildProcess) { if (typeof global !== 'undefined') { (global.pIds ??= []).push(process.pid); log(`Registered a process with id "${process.pid}"`); } else { throw new Error('"global" is not defined'); } } export function runCommandUntil( command: string, tmpDir: string, criteria: (output: string) => boolean ): Promise { const p = exec(command, { cwd: tmpDir, encoding: 'utf-8', }); registerExecutedChildProcess(p); return new Promise((res, rej) => { let output = ''; let complete = false; function checkCriteria(c: any) { output += c.toString(); console.warn(output); if (criteria(stripConsoleColors(output)) && !complete) { complete = true; res(p); } } p.stdout?.on('data', checkCriteria); p.stderr?.on('data', checkCriteria); p.on('exit', (code) => { if (!complete) { rej(`Exited with ${code}`); } else { res(p); } }); }); } function stripConsoleColors(log: string): string { return log.replace( // eslint-disable-next-line no-control-regex /[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, '' ); } export async function getPageHtml(pageUrl: string): Promise { const res = await fetch(pageUrl, { headers: { accept: 'text/html' } }).then((r) => r.text()); return createDocument({ html: res }); } export async function assertHostUnused(host: string): Promise { try { const response = await fetch(host, { headers: { accept: 'text/html' } }); } catch (error) { // TODO: test this in different environments if (error.cause.code === 'ECONNREFUSED') { return; } } throw new Error(`Host ${host} is already in use!`); } // promisify fails to get the proper type overload, so manually enforcing the type const _promisifiedTreeKill = promisify(treeKill) as (pid: number, signal: string) => Promise; export const promisifiedTreeKill = async (pid: number, signal: string) => { try { return await _promisifiedTreeKill(pid, signal); } catch (error) { // Don't treat process termination failures as test failures // This is especially important on Windows where processes may already be gone // or may not be properly terminated with tree-kill log(`Process ${pid} could not be killed, but continuing: ${error.message}`); return Promise.resolve(); } }; export async function killAllRegisteredProcesses() { const pIds = (global?.pIds as number[]) ?? []; const result = await Promise.allSettled(pIds.map((pId) => promisifiedTreeKill(pId, 'SIGKILL'))); const stringifiedResult = JSON.stringify( result.map((v, i) => ({ pId: pIds[i], status: v.status === 'fulfilled' ? 'success' : 'failure', })) ); log('Cleaned up processes invoked by e2e test: ' + stringifiedResult); } export const workspaceRoot = _computeWorkspaceRoot(process.cwd()); function _computeWorkspaceRoot(cwd: string) { if (dirname(cwd) === cwd) { return process.cwd(); } const packageJsonAtCwd = join(cwd, 'package.json'); if (existsSync(packageJsonAtCwd)) { const content = JSON.parse(readFileSync(packageJsonAtCwd, 'utf-8')); if (content.name === 'qwik-monorepo') { return cwd; } } return _computeWorkspaceRoot(dirname(cwd)); } export function log(text: string) { // eslint-disable-next-line no-console console.log(yellow('E2E: ' + text)); } export const DEFAULT_TIMEOUT = process.env.CI ? 120000 : 30000; ================================================ FILE: e2e/qwik-cli-e2e/utils/setup.ts ================================================ import { execSync } from 'child_process'; import { join } from 'path'; import { workspaceRoot } from '.'; import { existsSync, writeFileSync } from 'fs'; const packageCfg = { '@builder.io/qwik': { packagePath: 'packages/qwik', distPath: 'packages/qwik/dist', }, '@builder.io/qwik-city': { packagePath: 'packages/qwik-city', distPath: 'packages/qwik-city/lib', }, 'eslint-plugin-qwik': { packagePath: 'packages/eslint-plugin-qwik', distPath: 'packages/eslint-plugin-qwik/dist', }, }; function ensurePackageBuilt() { for (const [name, cfg] of Object.entries(packageCfg)) { if (!existsSync(join(workspaceRoot, cfg.distPath))) { throw new Error(`Looks like package "${name}" has not been built yet.`); } } } function packPackages() { const tarballPaths: { name: string; absolutePath: string }[] = []; const tarballOutDir = join(workspaceRoot, 'temp', 'tarballs'); for (const [name, cfg] of Object.entries(packageCfg)) { const out = execSync(`pnpm pack --json --pack-destination=${tarballOutDir}`, { cwd: join(workspaceRoot, cfg.packagePath), encoding: 'utf-8', }); const json = JSON.parse(out); tarballPaths.push({ name, absolutePath: json.filename }); } writeFileSync(join(tarballOutDir, 'paths.json'), JSON.stringify(tarballPaths)); } ensurePackageBuilt(); packPackages(); ================================================ FILE: e2e/qwik-cli-e2e/vite.config.ts ================================================ import { existsSync, mkdirSync } from 'fs'; import { resolve } from 'path'; import tsconfigPaths from 'vite-tsconfig-paths'; import { defineConfig } from 'vitest/config'; // if we're running in github CI if (process.env.CI) { // Workaround for npm/pnpm crashing in scaffoldQwikProject because "name is too long" const testPath = resolve(process.cwd(), 'e2e-test-tmp'); // Create base directory if it doesn't exist if (!existsSync(testPath)) { mkdirSync(testPath); } // Create subdirectories for each template type const templateTypes = ['empty', 'playground']; for (const type of templateTypes) { const templatePath = resolve(testPath, type); if (!existsSync(templatePath)) { mkdirSync(templatePath); } } process.env.TEMP_E2E_PATH = testPath; } export default defineConfig({ plugins: [tsconfigPaths({ root: '../../' })], test: { include: ['./tests/*.spec.?(c|m)[jt]s?(x)'], setupFiles: ['./utils/setup.ts'], // Run only one test at a time to avoid potential conflicts. // These tests interact directly with the filesystem and/or run processes on localhost, // which can lead to issues if multiple tests are executed simultaneously fileParallelism: false, }, }); ================================================ FILE: e2e/qwik-react-e2e/.gitignore ================================================ playwright-report dist logs server tmp ================================================ FILE: e2e/qwik-react-e2e/adapters/express/vite.config.ts ================================================ import { nodeServerAdapter } from '@builder.io/qwik-city/adapters/node-server/vite'; import { extendConfig } from '@builder.io/qwik-city/vite'; import baseConfig from '../../vite.config'; export default extendConfig(baseConfig, () => { return { build: { ssr: true, rollupOptions: { input: ['src/entry.express.tsx', '@qwik-city-plan'], }, }, plugins: [nodeServerAdapter({ name: 'express' })], }; }); ================================================ FILE: e2e/qwik-react-e2e/package.json ================================================ { "name": "qwik-react-test-app", "description": "Qwik react test app", "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0" }, "private": true, "devDependencies": { "@builder.io/qwik-react": "workspace:^", "@types/react": "18.3.3", "@types/react-dom": "18.3.0", "react": "18.3.1", "react-dom": "18.3.1" }, "scripts": { "build": "qwik build", "build.client": "vite build", "build.preview": "vite build --ssr src/entry.preview.tsx", "build.server": "vite build -c adapters/express/vite.config.ts", "build.types": "tsc --incremental --noEmit", "deploy": "vercel deploy", "dev": "vite --mode ssr", "dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force", "express": "pnpm build && pnpm serve", "fmt": "prettier --write .", "fmt.check": "prettier --check .", "lint": "eslint \"src/**/*.ts*\"", "preview": "qwik build preview && vite preview --open", "qwik": "qwik", "serve": "node server/entry.express", "start": "vite --open --mode ssr", "test": "playwright test", "test.debug": "playwright test --debug", "test.ui": "playwright test --ui" }, "type": "module" } ================================================ FILE: e2e/qwik-react-e2e/playwright.config.ts ================================================ import { defineConfig, devices } from '@playwright/test'; /** See https://playwright.dev/docs/test-configuration. */ export default defineConfig({ testDir: './tests', fullyParallel: true, forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? 1 : undefined, reporter: 'line', use: { baseURL: 'http://localhost:3000', // trace: 'on-first-retry', // screenshot: 'only-on-failure', // Increase timeouts for service worker operations actionTimeout: 10000, navigationTimeout: 10000, }, // Increase global timeout for service worker tests timeout: process.env.CI ? 120000 : 30000, projects: [ { name: 'chromium', use: { ...devices['Desktop Chrome'], }, }, // { // name: 'firefox', // use: { ...devices['Desktop Firefox'] }, // }, { name: 'webkit', use: { ...devices['Desktop Safari'] }, }, ], webServer: { command: 'npm run express', port: 3000, stdout: 'pipe', reuseExistingServer: !process.env.CI, timeout: process.env.CI ? 120000 : 30000, }, }); ================================================ FILE: e2e/qwik-react-e2e/src/components/counter/index.tsx ================================================ /** @jsxImportSource react */ import { useEffect, useState } from 'react'; import { qwikify$ } from '@builder.io/qwik-react'; interface IProps { onMount(): void; onUnmount(): void; } function Counter({ onMount, onUnmount }: IProps) { const [count, setCount] = useState(0); useEffect(() => { onMount(); return () => onUnmount(); }, []); return (
count {count}
); } export const QCounter = qwikify$(Counter, { eagerness: 'hover' }); ================================================ FILE: e2e/qwik-react-e2e/src/components/router-head/router-head.tsx ================================================ import { component$ } from '@builder.io/qwik'; import { useDocumentHead, useLocation } from '@builder.io/qwik-city'; export const RouterHead = component$(() => { const head = useDocumentHead(); const loc = useLocation(); return ( <> {head.title} {head.meta.map((m) => ( ))} {head.links.map((l) => ( ))} ); }); ================================================ FILE: e2e/qwik-react-e2e/src/entry.dev.tsx ================================================ /* * WHAT IS THIS FILE? * * Development entry point using only client-side modules: * - Do not use this mode in production! * - No SSR * - No portion of the application is pre-rendered on the server. * - All of the application is running eagerly in the browser. * - More code is transferred to the browser than in SSR mode. * - Optimizer/Serialization/Deserialization code is not exercised! */ import { render, type RenderOptions } from '@builder.io/qwik'; import Root from './root'; export default function (opts: RenderOptions) { return render(document, , opts); } ================================================ FILE: e2e/qwik-react-e2e/src/entry.express.tsx ================================================ /* * WHAT IS THIS FILE? * * It's the entry point for the Express HTTP server when building for production. * * Learn more about Node.js server integrations here: * - https://qwik.dev/docs/deployments/node/ * */ import { createQwikCity, type PlatformNode } from '@builder.io/qwik-city/middleware/node'; import 'dotenv/config'; import qwikCityPlan from '@qwik-city-plan'; import { manifest } from '@qwik-client-manifest'; import render from './entry.ssr'; import express from 'express'; import { fileURLToPath } from 'node:url'; import { join } from 'node:path'; declare global { type QwikCityPlatform = PlatformNode; } // Directories where the static assets are located const distDir = join(fileURLToPath(import.meta.url), '..', '..', 'dist'); const buildDir = join(distDir, 'build'); // Allow for dynamic port const PORT = process.env.PORT ?? 3000; // Create the Qwik City Node middleware const { router, notFound } = createQwikCity({ render, qwikCityPlan, manifest, // getOrigin(req) { // // If deploying under a proxy, you may need to build the origin from the request headers // // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Proto // const protocol = req.headers["x-forwarded-proto"] ?? "http"; // // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Forwarded-Host // const host = req.headers["x-forwarded-host"] ?? req.headers.host; // return `${protocol}://${host}`; // } }); // Create the express server // https://expressjs.com/ const app = express(); // Enable gzip compression // app.use(compression()); // Static asset handlers // https://expressjs.com/en/starter/static-files.html app.use(`/build`, express.static(buildDir, { immutable: true, maxAge: '1y' })); app.use(express.static(distDir, { redirect: false })); // Use Qwik City's page and endpoint request handler app.use(router); // Use Qwik City's 404 handler app.use(notFound); // Start the express server app.listen(PORT, () => { /* eslint-disable */ console.log(`Server started: http://localhost:${PORT}/`); }); ================================================ FILE: e2e/qwik-react-e2e/src/entry.preview.tsx ================================================ /* * WHAT IS THIS FILE? * * It's the bundle entry point for `npm run preview`. * That is, serving your app built in production mode. * * Feel free to modify this file, but don't remove it! * * Learn more about Vite's preview command: * - https://vitejs.dev/config/preview-options.html#preview-options * */ import { createQwikCity } from '@builder.io/qwik-city/middleware/node'; import qwikCityPlan from '@qwik-city-plan'; // make sure qwikCityPlan is imported before entry import render from './entry.ssr'; /** The default export is the QwikCity adapter used by Vite preview. */ export default createQwikCity({ render, qwikCityPlan }); ================================================ FILE: e2e/qwik-react-e2e/src/entry.ssr.tsx ================================================ /** * WHAT IS THIS FILE? * * SSR entry point, in all cases the application is rendered outside the browser, this entry point * will be the common one. * * - Server (express, cloudflare...) * - Npm run start * - Npm run preview * - Npm run build */ import { renderToStream, type RenderToStreamOptions } from '@builder.io/qwik/server'; import { manifest } from '@qwik-client-manifest'; import Root from './root'; export default function (opts: RenderToStreamOptions) { return renderToStream(, { manifest, ...opts, // Use container attributes to set attributes on the html tag. containerAttributes: { lang: 'en-us', ...opts.containerAttributes, }, // prefetchStrategy: { // implementation: { // linkInsert: "html-append", // linkRel: "modulepreload", // }, // }, serverData: { ...opts.serverData, }, }); } ================================================ FILE: e2e/qwik-react-e2e/src/root.tsx ================================================ import { component$ } from '@builder.io/qwik'; import { QwikCityProvider, RouterOutlet, ServiceWorkerRegister } from '@builder.io/qwik-city'; import { RouterHead } from './components/router-head/router-head'; export default component$(() => { /** * The root of a QwikCity site always start with the component, immediately * followed by the document's and . * * Don't remove the `` and `` elements. */ return ( {/* */} ); }); ================================================ FILE: e2e/qwik-react-e2e/src/routes/index.tsx ================================================ import { component$ } from '@builder.io/qwik'; import { type DocumentHead } from '@builder.io/qwik-city'; export default component$(() => { return <>render qwik; }); export const head: DocumentHead = { title: 'Welcome to Qwik', meta: [ { name: 'description', content: 'Qwik site description', }, ], }; ================================================ FILE: e2e/qwik-react-e2e/src/routes/layout.tsx ================================================ import { component$, Slot } from '@builder.io/qwik'; import { Link } from '@builder.io/qwik-city'; export default component$(() => { return ( <> qwik react
); }); ================================================ FILE: e2e/qwik-react-e2e/src/routes/react/index.tsx ================================================ /* eslint-disable no-console */ import { component$ } from '@builder.io/qwik'; import { type DocumentHead } from '@builder.io/qwik-city'; import { QCounter } from '~/components/counter'; export default component$(() => { return ( console.log('@@@@ Mount')} onUnmount$={() => console.log('@@@@ Unmount')} /> ); }); export const head: DocumentHead = { title: 'Welcome to React Qwik', meta: [ { name: 'description', content: 'React Qwik site description', }, ], }; ================================================ FILE: e2e/qwik-react-e2e/tests/express.spec.ts ================================================ import { expect, test } from '@playwright/test'; test.describe('[SSR]', () => { test('should NOT call unmount callback for non hydrated component', async ({ page }) => { page.on('console', () => { throw new Error("React component shouldn't hydrate"); }); await page.goto('/react'); expect(await page.getByTestId('count').innerText()).toBe('count 0'); // unmount await page.getByTestId('qwik-link').click(); await page.waitForURL('/', { waitUntil: 'networkidle' }); expect(await page.textContent('main')).toBe('render qwik'); }); test('should call unmount callback for hydrated component', async ({ page }) => { await page.goto('/react'); expect(await page.getByTestId('count').innerText()).toBe('count 0'); // hydrate const mountConsole = page.waitForEvent('console'); await page.getByTestId('test-component').hover(); // check if hydrated and called useEffect const mountMsg = await mountConsole; expect(await mountMsg.args()[0].jsonValue()).toBe('@@@@ Mount'); // check if react works await page.getByTestId('inc-btn').click(); expect(await page.getByTestId('count').innerText()).toBe('count 1'); // unmount const unmountConsole = page.waitForEvent('console'); await page.getByTestId('qwik-link').click(); const unmountMsg = await unmountConsole; expect(await unmountMsg.args()[0].jsonValue()).toBe('@@@@ Unmount'); }); }); test.describe('[CSR]', () => { test('should call unmount callback', async ({ page }) => { await page.goto('/'); // csr const mountConsole = page.waitForEvent('console'); await page.getByTestId('react-link').click(); await page.waitForURL('/react/', { waitUntil: 'networkidle' }); expect(await page.getByTestId('count').innerText()).toBe('count 0'); // check if called useEffect const mountMsg = await mountConsole; expect(await mountMsg.args()[0].jsonValue()).toBe('@@@@ Mount'); // check if react works await page.getByTestId('inc-btn').click(); expect(await page.getByTestId('count').innerText()).toBe('count 1'); // unmount const unmountConsole = page.waitForEvent('console'); await page.getByTestId('qwik-link').click(); await page.waitForURL('/', { waitUntil: 'networkidle' }); const unmountMsg = await unmountConsole; expect(await unmountMsg.args()[0].jsonValue()).toBe('@@@@ Unmount'); }); }); ================================================ FILE: e2e/qwik-react-e2e/tsconfig.json ================================================ { "compilerOptions": { "baseUrl": ".", "allowJs": true, "target": "ES2020", "module": "ES2022", "lib": ["es2022", "DOM", "WebWorker", "DOM.Iterable"], "jsx": "react-jsx", "jsxImportSource": "@builder.io/qwik", "strict": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, "moduleResolution": "Bundler", "esModuleInterop": true, "skipLibCheck": true, "incremental": true, "isolatedModules": true, "outDir": "tmp", "noEmit": true, "paths": { "~/*": ["./src/*"] } }, "include": ["src", "./*.d.ts", "./*.config.ts"] } ================================================ FILE: e2e/qwik-react-e2e/vite.config.ts ================================================ /** * This is the base config for vite. When building, the adapter config is used which loads this file * and extends it. */ import { qwikCity } from '@builder.io/qwik-city/vite'; import { qwikVite } from '@builder.io/qwik/optimizer'; import { qwikReact } from '@builder.io/qwik-react/vite'; import { defineConfig, type UserConfig } from 'vite'; import tsconfigPaths from 'vite-tsconfig-paths'; import pkg from './package.json'; type PkgDep = Record; const { dependencies = {}, devDependencies = {} } = pkg as any as { dependencies: PkgDep; devDependencies: PkgDep; [key: string]: unknown; }; errorOnDuplicatesPkgDeps(devDependencies, dependencies); /** * Note that Vite normally starts from `index.html` but the qwikCity plugin makes start at * `src/entry.ssr.tsx` instead. */ export default defineConfig((): UserConfig => { return { plugins: [qwikCity(), qwikVite(), tsconfigPaths({ root: '.' }), qwikReact()], // This tells Vite which dependencies to pre-build in dev mode. optimizeDeps: { // Put problematic deps that break bundling here, mostly those with binaries. // For example ['better-sqlite3'] if you use that in server functions. exclude: [], }, /** * This is an advanced setting. It improves the bundling of your server code. To use it, make * sure you understand when your consumed packages are dependencies or dev dependencies. * (otherwise things will break in production) */ // ssr: // command === "build" && mode === "production" // ? { // // All dev dependencies should be bundled in the server build // noExternal: Object.keys(devDependencies), // // Anything marked as a dependency will not be bundled // // These should only be production binary deps (including deps of deps), CLI deps, and their module graph // // If a dep-of-dep needs to be external, add it here // // For example, if something uses `bcrypt` but you don't have it as a dep, you can write // // external: [...Object.keys(dependencies), 'bcrypt'] // external: Object.keys(dependencies), // } // : undefined, server: { headers: { // Don't cache the server response in dev mode 'Cache-Control': 'public, max-age=0', }, }, preview: { headers: { // Do cache the server response in preview (non-adapter production build) 'Cache-Control': 'public, max-age=360', }, }, }; }); // *** utils *** /** * Function to identify duplicate dependencies and throw an error * * @param {Object} devDependencies - List of development dependencies * @param {Object} dependencies - List of production dependencies */ function errorOnDuplicatesPkgDeps(devDependencies: PkgDep, dependencies: PkgDep) { let msg = ''; // Create an array 'duplicateDeps' by filtering devDependencies. // If a dependency also exists in dependencies, it is considered a duplicate. const duplicateDeps = Object.keys(devDependencies).filter((dep) => dependencies[dep]); // include any known qwik packages const qwikPkg = Object.keys(dependencies).filter((value) => /qwik/i.test(value)); // any errors for missing "qwik-city-plan" // [PLUGIN_ERROR]: Invalid module "@qwik-city-plan" is not a valid package msg = `Move qwik packages ${qwikPkg.join(', ')} to devDependencies`; if (qwikPkg.length > 0) { throw new Error(msg); } // Format the error message with the duplicates list. // The `join` function is used to represent the elements of the 'duplicateDeps' array as a comma-separated string. msg = ` Warning: The dependency "${duplicateDeps.join(', ')}" is listed in both "devDependencies" and "dependencies". Please move the duplicated dependencies to "devDependencies" only and remove it from "dependencies" `; // Throw an error with the constructed message. if (duplicateDeps.length > 0) { throw new Error(msg); } } ================================================ FILE: eslint.config.js ================================================ import globals from 'globals'; import js from '@eslint/js'; import tseslint from 'typescript-eslint'; import noOnlyTests from 'eslint-plugin-no-only-tests'; import { globalIgnores } from 'eslint/config'; // import { qwikEslint9Plugin } from 'eslint-plugin-qwik'; const ignores = [ '**/.history', '**/.vscode', '**/dist', '**/dist-dev', '**/lib', '**/node_modules', '**/tsc-out', '**/external', '**/*.', '**/*.log', '**/etc', '**/target', '**/temp', '**/tsdoc-metadata.json', '**/.DS_Store', '**/*.mp4', 'scripts', '**/server/**/*.js', '**/*.tsbuildinfo', 'packages/docs/api', 'packages/docs/public/repl/repl-sw.js*', 'packages/docs/src/routes/examples/apps', 'packages/docs/src/routes/playground/app', 'packages/docs/src/routes/tutorial', 'packages/qwik/src/optimizer/core/src/fixtures', 'packages/qwik/bindings', 'packages/qwik-labs/lib', 'packages/qwik-labs/lib-types', 'packages/qwik-labs/vite', 'packages/insights/drizzle.config.ts', 'packages/insights/panda.config.ts', 'packages/qwik/src/napi', 'starters/apps/base', 'starters/apps/library', 'starters/templates', '**/vite.config.ts', // packages with eslint.config.mjs 'packages/qwik-labs', 'packages/insights', // eslint.config.* '**/eslint.config.mjs', '**/eslint.config.js', '.changeset', 'packages/docs/public/builder', ]; export default tseslint.config( globalIgnores(ignores), js.configs.recommended, tseslint.configs.recommended, // qwikEslint9Plugin.configs.recommended, { languageOptions: { globals: { ...globals.browser, ...globals.node, ...globals.es2021, }, parserOptions: { // Needed when using the qwik plugin // projectService: true, // tsconfigRootDir: import.meta.dirname, }, }, }, { plugins: { 'no-only-tests': noOnlyTests, }, rules: { 'no-only-tests/no-only-tests': 'error', }, name: 'no-only-tests', }, { rules: { '@typescript-eslint/no-explicit-any': 'off', '@typescript-eslint/explicit-module-boundary-types': 'off', '@typescript-eslint/no-inferrable-types': 'off', '@typescript-eslint/no-non-null-assertion': 'off', '@typescript-eslint/no-empty-interface': 'off', '@typescript-eslint/no-namespace': 'off', '@typescript-eslint/no-empty-function': 'off', '@typescript-eslint/no-this-alias': 'off', '@typescript-eslint/ban-types': 'off', '@typescript-eslint/ban-ts-comment': 'off', 'prefer-spread': 'off', 'no-case-declarations': 'off', 'no-console': ['error', { allow: ['warn', 'error'] }], 'no-only-tests/no-only-tests': 'error', '@typescript-eslint/no-unused-vars': 'off', '@typescript-eslint/no-var-requires': 'off', curly: 'error', 'no-new-func': 'error', '@typescript-eslint/no-empty-object-type': 'off', '@typescript-eslint/no-unused-expressions': 'off', '@typescript-eslint/no-unsafe-function-type': 'off', '@typescript-eslint/no-require-imports': 'off', '@typescript-eslint/no-wrapper-object-types': 'off', }, }, { files: ['packages/docs/**/*.{ts,tsx}'], rules: { 'no-console': 'off', }, } ); ================================================ FILE: flake.nix ================================================ # This is a Nix configuration file. It is used to define the environment # for the project. It is a declarative way to define the dependencies. # It is used by the `nix develop` command to create a development environment # with all the dependencies needed for the project. # To update the dependencies, run `nix flake update`. # Note: keep the playwright version in package.json syncpack the same as the nix version # We don't need to have the latest playwright all the time so not having to download # all the browsers on every version bump is a good thing. { inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; rust-overlay.url = "github:oxalica/rust-overlay"; }; outputs = { self, rust-overlay, nixpkgs }: let b = builtins; devShell = system: _pkgs: let overlays = [ (import rust-overlay) ]; pkgs = import nixpkgs { inherit system overlays; }; in { default = pkgs.mkShell { nativeBuildInputs = with pkgs; [ bashInteractive gitMinimal nodejs_22 corepack_22 # Playwright for the end-to-end tests playwright-driver.browsers # Qwik optimizer deps wasm-pack # Provides rustc and cargo ((rust-bin.fromRustupToolchainFile ./rust-toolchain).override { # For rust-analyzer extensions = [ "rust-src" ]; # For building wasm targets = [ "wasm32-unknown-unknown" ]; }) ]; # https://github.com/microsoft/playwright/issues/5501 shellHook = '' export PATH=$PWD/node_modules/.bin:$PATH export PLAYWRIGHT_BROWSERS_PATH=${pkgs.playwright-driver.browsers} export PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS=true pwNixVersion=${pkgs.playwright-driver.version} pwNpmVersion=$(${pkgs.jq}/bin/jq -r .version node_modules/@playwright/test/package.json 2>/dev/null) if [ -n "$pwNpmVersion" ] && [ "$pwNpmVersion" != "$pwNixVersion" ]; then echo "!!! Playwright version mismatch: $pwNpmVersion (nodejs) != $pwNixVersion (nix). Please fix." >&2 fi ''; }; }; in { devShells = b.mapAttrs (devShell) nixpkgs.legacyPackages; }; } ================================================ FILE: package.json ================================================ { "name": "qwik-monorepo", "version": "0.0.0-read-qwik-package-json", "comments": { "01": "devDependencies includes reference to @builder.io/qwik: workspace: *. This is needed or e2e tests will fail", "02": " It would be nice to be able to remove this dependency and fix the test.", "03": "devDependencies can't include reference to @builder.io/qwik-city or e2e test will fail." }, "config": { "syncpack": { "versionGroups": [ { "label": "Be lenient in vite versions for prod. v4 is broken, v5 is good", "dependencyTypes": [ "prod", "peer" ], "dependencies": [ "vite" ], "pinVersion": ">=5 <8" }, { "label": "use workspace protocol for local packages and allow patch versions (used in e.g. qwik-react)", "dependencies": [ "$LOCAL" ], "dependencyTypes": [ "!local", "!dev" ], "pinVersion": "workspace:^" }, { "label": "dev: use workspace protocol for local packages - split from prod and peer version group", "dependencies": [ "$LOCAL" ], "dependencyTypes": [ "dev" ], "pinVersion": "workspace:^" }, { "label": "Separate prod deps from dev deps", "dependencyTypes": [ "prod", "peer" ] }, { "label": "Playwright should have the same version as in flake.nix", "dependencies": [ "@playwright/test" ], "dependencyTypes": [ "dev" ], "pinVersion": "1.54.1" } ], "semverGroups": [ { "label": "Undici should always be * until we remove it", "dependencies": [ "undici" ], "range": "*" }, { "label": "use exact version numbers for devDependencies", "dependencyTypes": [ "dev" ], "range": "" } ] } }, "contributors": [ { "name": "Miško Hevery", "email": "misko@hevery.com", "url": "https://twitter.com/mhevery" }, { "name": "Adam Bradley", "email": "adam@builder.io", "url": "https://twitter.com/adamdbradley" }, { "name": "Manu Mtz.-Almeida", "email": "manu@builder.io", "url": "https://twitter.com/manucorporat" } ], "dependencies": { "esbuild-plugin-raw": "^0.2.0" }, "devDependencies": { "@builder.io/qwik": "workspace:^", "@builder.io/qwik-city": "workspace:^", "@changesets/cli": "2.29.5", "@changesets/get-github-info": "0.6.0", "@changesets/types": "6.1.0", "@clack/prompts": "0.7.0", "@eslint/js": "9.32.0", "@mdx-js/mdx": "3.1.1", "@microsoft/api-documenter": "7.26.31", "@microsoft/api-extractor": "7.52.10", "@napi-rs/cli": "2.18.4", "@napi-rs/triples": "1.2.0", "@node-rs/helper": "1.6.0", "@octokit/action": "6.1.0", "@playwright/test": "1.54.1", "@qwik.dev/partytown": "0.11.2", "@types/brotli": "1.3.4", "@types/bun": "1.2.19", "@types/cross-spawn": "6.0.6", "@types/express": "4.17.21", "@types/node": "20.19.0", "@types/path-browserify": "1.0.3", "@types/prompts": "2.4.9", "@types/react": "18.3.3", "@types/semver": "7.7.0", "@types/tmp": "0.2.6", "@types/which-pm-runs": "1.0.2", "@vitejs/plugin-basic-ssl": "2.1.0", "all-contributors-cli": "6.26.1", "brotli": "1.3.3", "create-qwik": "workspace:^", "cross-spawn": "7.0.6", "csstype": "3.1.3", "dotenv": "16.5.0", "esbuild": "0.25.10", "eslint": "9.32.0", "eslint-plugin-no-only-tests": "3.3.0", "eslint-plugin-qwik": "workspace:^", "execa": "9.6.0", "express": "4.22.0", "globals": "16.4.0", "install": "0.13.0", "memfs": "4.49.0", "monaco-editor": "0.45.0", "mri": "1.2.0", "path-browserify": "1.0.1", "prettier": "3.6.2", "prettier-plugin-jsdoc": "1.3.3", "prettier-plugin-tailwindcss": "0.6.14", "pretty-quick": "4.2.2", "prompts": "2.4.2", "rollup": "4.59.0", "semver": "7.7.2", "simple-git-hooks": "2.13.1", "snoop": "1.0.4", "source-map": "0.7.6", "svgo": "3.3.3", "syncpack": "12.3.3", "terser": "5.44.0", "tmp": "0.2.5", "tree-kill": "1.2.2", "typescript": "5.4.5", "typescript-eslint": "8.38.0", "undici": "*", "vfile": "6.0.3", "vite": "7.3.1", "vite-imagetools": "9.0.0", "vite-plugin-dts": "3.9.1", "vite-tsconfig-paths": "5.1.4", "vitest": "3.2.4", "watchlist": "0.3.1", "which-pm-runs": "1.1.0", "zod": "3.25.48" }, "engines": { "node": ">=22.18.0", "npm": "please-use-pnpm", "yarn": "please-use-pnpm", "pnpm": ">=10.14.0" }, "packageManager": "pnpm@10.14.0", "private": true, "scripts": { "api.update": "node --require ./scripts/runBefore.ts scripts/index.ts --tsc --api --dev", "build": "node --require ./scripts/runBefore.ts scripts/index.ts", "build.changelog-formatter": "tsc .changeset/changelog-github-custom.ts && mv .changeset/changelog-github-custom.js .changeset/changelog-github-custom.cjs", "build.clean": "node ./scripts/build-clean.ts", "build.cli": "node --require ./scripts/runBefore.ts scripts/index.ts --cli --dev", "build.cli.prod": "node --require ./scripts/runBefore.ts scripts/index.ts --cli", "build.core": "node --require ./scripts/runBefore.ts scripts/index.ts --tsc --build --qwikcity --api --platform-binding", "build.eslint": "node --require ./scripts/runBefore.ts scripts/index.ts --eslint", "build.full": "node --require ./scripts/runBefore.ts scripts/index.ts --tsc --tsc-docs --build --supabaseauthhelpers --api --eslint --qwikcity --qwikworker --qwiklabs --qwikreact --qwikauth --cli --platform-binding --wasm", "build.local": "node --require ./scripts/runBefore.ts scripts/index.ts --tsc --tsc-docs --build --supabaseauthhelpers --api --eslint --qwikcity --qwikworker --qwiklabs --qwikreact --qwikauth --cli --platform-binding-wasm-copy", "build.only_javascript": "node --require ./scripts/runBefore.ts scripts/index.ts --tsc --build --api", "build.packages.docs": "pnpm -C ./packages/docs/ run build", "build.packages.insights": "pnpm -C ./packages/insights/ run build", "build.platform": "node --require ./scripts/runBefore.ts scripts/index.ts --platform-binding", "build.platform.copy": "node --require ./scripts/runBefore.ts scripts/index.ts --platform-binding-wasm-copy", "build.qwik-city": "node --require ./scripts/runBefore.ts scripts/index.ts --tsc --qwikcity", "build.qwik-react": "node --require ./scripts/runBefore.ts scripts/index.ts --tsc --qwikreact", "build.validate": "node --require ./scripts/runBefore.ts scripts/index.ts --tsc --build --api --eslint --qwikcity --platform-binding --wasm --validate", "build.vite": "node --require ./scripts/runBefore.ts scripts/index.ts --tsc --build --api --qwikcity --eslint --platform-binding-wasm-copy", "build.wasm": "node --require ./scripts/runBefore.ts scripts/index.ts --wasm", "build.watch": "node --require ./scripts/runBefore.ts scripts/index.ts --build --qwikcity --watch --dev --platform-binding", "change": "changeset", "cli": "pnpm build.cli && node packages/create-qwik/create-qwik.cjs && node --require ./scripts/runBefore.ts scripts/validate-cli.ts --copy-local-qwik-dist", "cli.qwik": "pnpm build.cli && node packages/qwik/qwik-cli.cjs", "cli.validate": "node --require ./scripts/runBefore.ts scripts/validate-cli.ts", "deps": "corepack pnpm upgrade -i -r --latest && syncpack fix-mismatches && corepack pnpm dedupe", "docs.dev": "pnpm -C packages/docs build.repl-sw && pnpm -C packages/docs dev", "docs.preview": "pnpm -C packages/docs preview", "docs.sync": "node --require ./scripts/runBefore.ts scripts/docs_sync/index.ts && pnpm fmt", "docs.showcase": "pnpm -C packages/docs run build.showcase", "eslint.update": "node --require ./scripts/runBefore.ts scripts/eslint-docs.ts", "fmt": "pnpm prettier.fix && pnpm syncpack format", "fmt.staged": "pretty-quick --staged", "link.dist": "cd packages/qwik && pnpm link --global && cd ../qwik-city && pnpm link --global && cd ../eslint-plugin-qwik && pnpm link --global && cd ../qwik-react && pnpm link --global", "link.dist.npm": "cd packages/qwik && npm link && cd ../qwik-city && npm link && cd ../eslint-plugin-qwik && npm link && cd ../qwik-react && npm link", "link.dist.yarn": "cd packages/qwik && yarn link && cd ../qwik-city && yarn link && cd ../eslint-plugin-qwik && yarn link && cd ../qwik-react && yarn link", "lint": "pnpm lint.eslint && pnpm lint.prettier && pnpm lint.rust", "lint.eslint": "eslint --cache \"**/*.ts*\" && pnpm -r --parallel lint", "lint.fix": "eslint --fix \"**/*.ts*\" && pnpm -r --parallel lint.fix && pnpm prettier.fix", "lint.prettier": "prettier --cache --check .", "lint.rust": "make lint", "lint.syncpack": "syncpack list-mismatches", "preinstall": "npx only-allow pnpm", "prepare": "simple-git-hooks", "prettier.fix": "prettier --cache --write .", "qwik-push-build-repos": "node --require ./scripts/runBefore.ts ./scripts/qwik-push-build-repos.ts", "release": "changeset publish", "release.fixup-package-json": "syncpack fix-mismatches --config syncpack-release-conf.json", "release.pkg-pr-new": "pnpm dlx pkg-pr-new@^0.0.9 publish --compact --pnpm ./packages/qwik ./packages/qwik-city ./packages/eslint-plugin-qwik ./packages/create-qwik", "release.prepare": "pnpm build --prepare-release", "serve": "node --require ./scripts/runBefore.ts --inspect --conditions=development starters/dev-server.ts 3300", "serve.debug": "node --require ./scripts/runBefore.ts --inspect-brk --conditions=development starters/dev-server.ts 3300", "start": "pnpm run --stream \"/.*\\.watch/\"", "test": "pnpm build.full && pnpm test.unit && pnpm test.e2e", "test.e2e": "pnpm test.e2e.chromium && pnpm test.e2e.webkit && test.e2e.integrations", "test.e2e.chromium": "playwright test starters --browser=chromium --config starters/playwright.config.ts", "test.e2e.chromium.debug": "PWDEBUG=1 playwright test starters --browser=chromium --config starters/playwright.config.ts", "test.e2e.city": "playwright test starters/e2e/qwikcity --browser=chromium --config starters/playwright.config.ts", "test.e2e.cli": "pnpm --filter qwik-cli-e2e e2e", "test.e2e.firefox": "playwright test starters --browser=firefox --config starters/playwright.config.ts", "test.e2e.integrations.chromium": "playwright test e2e/adapters-e2e/tests --project=chromium --config e2e/adapters-e2e/playwright.config.ts", "test.e2e.integrations.webkit": "playwright test e2e/adapters-e2e/tests --project=webkit --config e2e/adapters-e2e/playwright.config.ts", "test.e2e.webkit": "playwright test starters --browser=webkit --config starters/playwright.config.ts", "test.e2e.qwik-react.chromium": "playwright test e2e/qwik-react-e2e/tests --project=chromium --config e2e/qwik-react-e2e/playwright.config.ts", "test.e2e.qwik-react.webkit": "playwright test e2e/qwik-react-e2e/tests --project=webkit --config e2e/qwik-react-e2e/playwright.config.ts", "test.rust": "make test", "test.rust.update": "make test-update", "test.unit": "vitest packages", "test.unit.debug": "vitest --inspect-brk packages", "test.vite": "playwright test starters/e2e/qwikcity --browser=chromium --config starters/playwright.config.ts", "tsc.check": "tsc --noEmit", "tsc.trace": "tsc -p tsconfig.json --traceResolution > tsc.log", "tsc.watch": "tsc --noEmit --watch --preserveWatchOutput", "update.qwik.builds": "node --require ./scripts/runBefore.ts scripts/update-qwik-builds.ts packages/docs && node scripts/update-qwik-builds.ts packages/insights; pnpm install", "vitest": "vitest" }, "simple-git-hooks": { "pre-commit": "pnpm pretty-quick --staged" }, "type": "module" } ================================================ FILE: packages/create-qwik/.npmignore ================================================ src ================================================ FILE: packages/create-qwik/CHANGELOG.md ================================================ # create-qwik ## 1.19.0 ### Patch Changes - ✨ cloudflare workers deployment adapter (by [@LazyClicks](https://github.com/LazyClicks) in [#8214](https://github.com/QwikDev/qwik/pull/8214)) ## 1.18.0 ### Patch Changes - execute cleanup cb for all component tree while calling dispose.cleanup method returned by render fn (by [@sashkashishka](https://github.com/sashkashishka) in [#8164](https://github.com/QwikDev/qwik/pull/8164)) ## 1.17.2 ## 1.17.1 ## 1.17.0 ## 1.16.1 ### Patch Changes - 🐞🩹 set sideEffects: false to the lib template, otherwise there might be some side effects imports when building a consumer project. (by [@gioboa](https://github.com/gioboa) in [#7855](https://github.com/QwikDev/qwik/pull/7855)) - 🐞🩹 fix up vscode settings merge. Use JSON5 to parse settings.json to prevent parsing errors. (by [@gioboa](https://github.com/gioboa) in [#7858](https://github.com/QwikDev/qwik/pull/7858)) - 🛠 use the new version of @croct/json5-parser to merge JSON5 and preserve comments (by [@gioboa](https://github.com/gioboa) in [#7884](https://github.com/QwikDev/qwik/pull/7884)) ## 1.16.0 ### Minor Changes - ✨ bump Vite to v7 (by [@gioboa](https://github.com/gioboa) in [#7762](https://github.com/QwikDev/qwik/pull/7762)) ### Patch Changes - 🐞🩹 fix up TypeScript compatibility in the localize starter (by [@FDiskas](https://github.com/FDiskas) in [#7617](https://github.com/QwikDev/qwik/pull/7617)) ## 1.15.0 ### Patch Changes - 🐞🩹 fix up vercel starter config (by [@cmbartschat](https://github.com/cmbartschat) in [#7663](https://github.com/QwikDev/qwik/pull/7663)) - 🛠 update devDependencies and configurations (by [@JerryWu1234](https://github.com/JerryWu1234) in [#7695](https://github.com/QwikDev/qwik/pull/7695)) ## 1.14.1 ### Patch Changes - 🐞🩹 starter app missing package and added preview cli test (by [@wmertens](https://github.com/wmertens) in [#7626](https://github.com/QwikDev/qwik/pull/7626)) ## 1.14.0 ### Patch Changes - 🐞🩹 create-qwik logAppCreated.ts now displays correct next steps for deno. (by [@LogProphet](https://github.com/LogProphet) in [#7566](https://github.com/QwikDev/qwik/pull/7566)) After using the create-qwik command, the logAppCreated.ts file was not displaying the correct next steps for deno. Prior to this fix it would display "deno start" instead of "deno task start". This would cause a failure to run, as deno requires the 'task' keyword. This fixes bug 7520 - 🐞🩹 linting errors which were previously being ignored across the monorepo. (by [@better-salmon](https://github.com/better-salmon) in [#7418](https://github.com/QwikDev/qwik/pull/7418)) ## 1.13.0 ## 1.12.1 ## 1.12.0 ## 1.11.0 ## 1.10.0 ### Patch Changes - INFRA: migration from tsm to tsx (by [@JerryWu1234](https://github.com/JerryWu1234) in [#6877](https://github.com/QwikDev/qwik/pull/6877)) ## 1.9.1 ## 1.9.0 ### Patch Changes - ✨ tailwind starter dependencies upgraded to latest (by [@thejackshelton](https://github.com/thejackshelton) in [#6783](https://github.com/QwikDev/qwik/pull/6783)) - ✨ added `preserveModules` to library starters to improve library bundling / tree-shaking (by [@thejackshelton](https://github.com/thejackshelton) in [#6773](https://github.com/QwikDev/qwik/pull/6773)) ## 1.8.0 ### Patch Changes - 🐞🩹 wrong version when creating a library (by [@shairez](https://github.com/shairez) in [#6757](https://github.com/QwikDev/qwik/pull/6757)) ## 1.7.3 ### Patch Changes - 🐞🩹 get the right version number in starter apps (by [@shairez](https://github.com/shairez) in [#6742](https://github.com/QwikDev/qwik/pull/6742)) ## 1.7.2 ### Patch Changes - - built files are now under dist/ or lib/. All tools that respect package export maps should just work. (by [@wmertens](https://github.com/wmertens) in [#6715](https://github.com/QwikDev/qwik/pull/6715)) If you have trouble with Typescript, ensure that you use `moduleResolution: "Bundler"` in your `tsconfig.json`. - `@builder.io/qwik` no longer depends on `undici` ================================================ FILE: packages/create-qwik/README.md ================================================ # Create Qwik ⚡️ ## Interactive mode ``` npm create qwik@latest ``` ## Command mode ``` npm create qwik@latest ``` ## API ```javascript const { createApp } = require('create-qwik'); const opts = { projectName: 'my-project', starterId: 'todo', outDir: '/path/to/output/dir', }; const result = await createApp(opts); console.log(result); ``` ## Community - Ping us at [@QwikDev](https://twitter.com/QwikDev) - Join our [Discord](https://qwik.dev/chat) community ## Related - [Qwik](https://qwik.dev/) - [Partytown](https://partytown.qwik.dev) - [Mitosis](https://github.com/BuilderIO/mitosis) - [Builder.io](https://github.com/BuilderIO/) ================================================ FILE: packages/create-qwik/create-qwik.cjs ================================================ #!/usr/bin/env node const createQwik = require('./dist/index.cjs'); createQwik.runCli(); ================================================ FILE: packages/create-qwik/index.ts ================================================ import { runCreateCli } from './src/run-create-cli'; import { runCreateInteractiveCli } from './src/run-create-interactive-cli'; import { panic, printHeader } from '../qwik/src/cli/utils/utils'; import { red, yellow } from 'kleur/colors'; import { createAppFacade } from './src/create-app-facade'; export async function runCli() { printHeader(); checkNodeVersion(); try { const args = process.argv.slice(2); if (args.length > 0) { await runCreateCli(...args); } else { // npm create qwik await runCreateInteractiveCli(); } } catch (e: any) { panic(e.message || e); } } function checkNodeVersion() { const version = process.version; const [majorVersion, minorVersion] = version.replace('v', '').split('.'); if (Number(majorVersion) < 16) { console.error( red(`Qwik requires Node.js 16.8 or higher. You are currently running Node.js ${version}.`) ); process.exit(1); } else if (Number(majorVersion) === 16) { if (Number(minorVersion) < 8) { console.warn( yellow( `Node.js 16.8 or higher is recommended. You are currently running Node.js ${version}.` ) ); } } else if (Number(majorVersion) === 18) { if (Number(minorVersion) < 11) { console.error( red( `Node.js 18.11 or higher is REQUIRED. From Node 18.0.0 to 18.11.0, there is a bug preventing correct behavior of Qwik. You are currently running Node.js ${version}. https://github.com/QwikDev/qwik/issues/3035` ) ); } } } export { createAppFacade as createApp, runCreateCli, runCreateInteractiveCli }; ================================================ FILE: packages/create-qwik/package.json ================================================ { "name": "create-qwik", "description": "Interactive CLI for create Qwik projects and adding features.", "version": "1.19.0", "author": "Builder.io Team", "bin": "./create-qwik.cjs", "bugs": "https://github.com/QwikDev/qwik/issues", "devDependencies": { "@clack/prompts": "0.7.0", "@types/yargs": "17.0.33", "kleur": "4.1.5", "yargs": "17.7.2" }, "engines": { "node": "^18.17.0 || ^20.3.0 || >=21.0.0", "npm": ">=10.0.0", "pnpm": ">=8.0.0", "yarn": ">=3.0.0" }, "engines-annotation": "Mostly required by sharp which needs a Node-API v9 compatible runtime", "files": [ "README.md", "create-qwik.cjs", "dist" ], "homepage": "https://qwik.dev/", "keywords": [ "builder.io", "generator", "qwik", "starters", "template" ], "license": "MIT", "main": "./dist/index.cjs", "repository": { "type": "git", "url": "https://github.com/QwikDev/qwik.git", "directory": "packages/create-qwik" } } ================================================ FILE: packages/create-qwik/src/create-app-facade.ts ================================================ import type { CreateAppOptions, CreateAppResult } from '../../qwik/src/cli/types'; import { createApp } from './create-app'; import { getPackageManager } from '../../qwik/src/cli/utils/utils'; import { makeTemplateManager } from './helpers/templateManager'; export async function createAppFacade(opts: CreateAppOptions): Promise { const pkgManager = getPackageManager(); const templateManager = await makeTemplateManager('app'); return await createApp({ appId: opts.starterId, templateManager, outDir: opts.outDir, pkgManager, }); } ================================================ FILE: packages/create-qwik/src/create-app.ts ================================================ import type { CreateAppResult, IntegrationData } from '../../qwik/src/cli/types'; import fs from 'node:fs'; import { isAbsolute, join } from 'node:path'; import { cleanPackageJson, writePackageJson } from '../../qwik/src/cli/utils/utils'; import { updateApp } from '../../qwik/src/cli/add/update-app'; import { type TemplateManager } from './helpers/templateManager'; type Options = { appId: string; templateManager: TemplateManager; outDir: string; pkgManager: string; }; type CreateFromStarterOptions = { pkgManager: string; baseApp: IntegrationData; starterApp?: IntegrationData; outDir: string; }; function isValidOption(value: any) { return typeof value === 'string' && value.trim().length > 0; } function validateOptions(opts: Options) { if (!isValidOption(opts.outDir)) { throw new Error(`Missing outDir`); } if (!isAbsolute(opts.outDir)) { throw new Error(`outDir must be an absolute path`); } } export async function createApp(opts: Options): Promise { const { appId, outDir, pkgManager, templateManager } = opts; const { baseApp, starterApp } = templateManager.getBootstrapApps(appId); validateOptions(opts); if (!fs.existsSync(outDir)) { fs.mkdirSync(decodeURIComponent(outDir), { recursive: true }); } const docs = await createFromStarter({ baseApp, starterApp, pkgManager, outDir }); return { starterId: opts.appId, outDir, pkgManager, docs }; } async function createFromStarter({ baseApp, starterApp, outDir, pkgManager, }: CreateFromStarterOptions): Promise { const docs = [...baseApp.docs]; const appInfo = starterApp ?? baseApp; const appPkgJson = cleanPackageJson({ ...baseApp.pkgJson, name: `my-${appInfo.pkgJson.name}`, description: appInfo.pkgJson.description, scripts: undefined, dependencies: undefined, devDependencies: undefined, }); await writePackageJson(outDir, appPkgJson); const readmePath = join(outDir, 'README.md'); await fs.promises.writeFile(readmePath, ''); const baseUpdate = await updateApp(pkgManager, { rootDir: outDir, integration: baseApp.id, installDeps: false, }); await baseUpdate.commit(false); if (starterApp) { docs.push(...starterApp.docs); const starterUpdate = await updateApp(pkgManager, { rootDir: outDir, integration: starterApp.id, installDeps: false, }); await starterUpdate.commit(false); } return docs; } ================================================ FILE: packages/create-qwik/src/helpers/clearDir.ts ================================================ import fs from 'node:fs'; import { join } from 'node:path'; export const clearDir = async (dir: string) => { const files = await fs.promises.readdir(dir); return await Promise.all( files.map((pathToFile) => fs.promises.rm(join(dir, pathToFile), { recursive: true })) ); }; ================================================ FILE: packages/create-qwik/src/helpers/installDepsCli.ts ================================================ import type { spinner } from '@clack/prompts'; type Sinner = ReturnType; type Params = { spinner: Sinner; pkgManager: string; }; export async function installDepsCli(fn: () => Promise, { pkgManager, spinner }: Params) { spinner.start(`Installing ${pkgManager} dependencies...`); const success = await fn(); spinner.stop(`${success ? 'Installed' : 'Failed to install'} ${pkgManager} dependencies 📋`); return success; } ================================================ FILE: packages/create-qwik/src/helpers/jokes.json ================================================ [ ["What's the best thing about a Boolean?", "Even if you're wrong, you're only off by a bit."], ["Why did the developer stay at home?", "Because he couldn't find his keys."], ["How many programmers does it take to change a lightbulb?", "None that's a hardware problem"], ["A user interface is like a joke.", "If you have to explain it then it is not that good."], ["['hip', 'hip']", "(hip hip array)"], ["A SQL query goes into a bar, walks up to two tables and asks:", "'Can I JOIN you?'"], ["Why did the developer go to therapy?", "He had too many unresolved issues."], [ "Why do C# and Java developers keep breaking their keyboards?", "Because they use a strongly typed language." ], ["What's the object-oriented way to become wealthy?", "Inheritance"], ["Where do programmers like to hangout?", "The Foo Bar."], ["Why do Java programmers wear glasses?", "Because they don't C#"], ["To understand what recursion is...", "You must first understand what recursion is"], ["The punchline often arrives before the set-up.", "Do you know the problem with UDP jokes?"], ["Why did the programmer quit his job?", "Because he didn't get arrays."], ["Why was the computer tired when it got home?", "It had a hard drive."], [ "There are 10 types of people in this world...", "Those who understand binary and those who don't" ], ["Why do programmers always mix up Halloween and Christmas?", "Because Oct 31 == Dec 25"], ["I was gonna tell you a joke about UDP...", "...but you might not get it."], ["Normal People: give me just a second", "Developers: give me 1000 milliseconds!"], ["Why do programmers prefer dark mode?", "Because light attracts bugs."], ["Why don't programmers like nature?", "It has too many bugs."], ["Why was the computer freezing?", "It left its Windows open!"], ["What did the Java code say to the C code?", "You've got no class."], ["Why do programmers prefer the outdoors?", "Because it's free of bugs."], ["Why do programmers love movies?", "Because they can 'script' the ending."], ["why do desert animals hate Qwik?", "Because there's no hydration...."], ["What can you do if you cannot push your git changes?", "Use the --force, Luke"], ["How did the developer announce he's getting married?", "'She returned true!'"], ["How many Prolog programmers does it take to change a lightbulb?", "Yes."], ["Why did the developer ground their kid?", "They weren't telling the truthy"], ["!false", "It's funny 'cause it's true."], ["Where did the parallel function wash its hands?", "Async"], ["How do functions break up?", "They stop calling each other"], ["Why did the functions stop calling each other?", "Because they had constant arguments."], ["What's the second movie about a database engineer called?", "The SQL."], ["What did the computer do at lunchtime?", "NoSQL."], ["Why doesn't Hollywood make more Big Data movies?", "Had a byte!"], ["What does a baby computer call his father?", "Data!"], ["I never tell the same joke twice", "I have a DRY sense of humor."], ["How do programming pirates pass method parameters?", "ARRRRRGS."], ["Why don't bachelors like Git?", "Because they are afraid to commit."], ["Why do astronauts use Linux?", "They can't open Windows in space!"], ["How do front end devs like their brownies?", "GUI"], ["What do hackers do on a boat?", "Phishing."], ["Why couldn't the HTML list be trusted?", "There were LI's everywhere"], ["To the person who invented zero:", "Thank's for nothing!"], ["What do you call a bee that lives in America?", "A USB"], ["want about to a race conditions hear joke?", ""], ["What is a Package Managers favorite holiday?", "Dependency Day"], ["Where do we get all of these dad jokes from?", "A dad-a-base!"], ["What advice do you give to a JS developer who has never played baseball?", "Try catch."], ["We don't have any DNS jokes, know why?", "Because it may take 24 hours to get them"], ["Why do Front-End Developers eat lunch alone?", "Because they don't know how to join tables."], ["How do you help JS errors?", "You `console` them!"], ["When do front end developers go out to eat?", "On their lunch
."], ["What do you call optimistic front-end developers?", "Stack half-full developers."] ] ================================================ FILE: packages/create-qwik/src/helpers/jokes.ts ================================================ import jokes from './jokes.json'; export function getRandomJoke() { const index = Math.floor(Math.random() * jokes.length); return jokes[index]!; } ================================================ FILE: packages/create-qwik/src/helpers/logAppCreated.ts ================================================ import { bgMagenta, bold, cyan, magenta } from 'kleur/colors'; import type { CreateAppResult } from '../../../qwik/src/cli/types'; import { logSuccessFooter } from '../../../qwik/src/cli/utils/log'; import { note } from '../../../qwik/src/cli/utils/utils'; import { outro } from '@clack/prompts'; import { relative } from 'node:path'; export function logAppCreated(pkgManager: string, result: CreateAppResult, ranInstall: boolean) { const isCwdDir = process.cwd() === result.outDir; const relativeProjectPath = relative(process.cwd(), result.outDir); const outString = []; if (isCwdDir) { outString.push(`🦄 ${bgMagenta(' Success! ')}`); } else { outString.push( `🦄 ${bgMagenta(' Success! ')} ${cyan(`Project created in`)} ${bold( magenta(relativeProjectPath) )} ${cyan(`directory`)}` ); } outString.push(``); const qwikAdd = pkgManager !== 'npm' ? `${pkgManager} qwik add` : `npm run qwik add`; outString.push(`🤍 ${cyan('Integrations? Add Netlify, Cloudflare, Tailwind...')}`); outString.push(` ${qwikAdd}`); outString.push(``); outString.push(logSuccessFooter(result.docs)); outString.push(`👀 ${cyan('Presentations, Podcasts and Videos:')}`); outString.push(` https://qwik.dev/media/`); outString.push(``); outString.push(`🐰 ${cyan(`Next steps:`)}`); if (!isCwdDir) { outString.push(` cd ${relativeProjectPath}`); } if (!ranInstall) { outString.push(` ${pkgManager} install`); } if (pkgManager === 'deno') { outString.push(` deno task start`); } else { outString.push(` ${pkgManager} start`); } outString.push(``); note(outString.join('\n'), 'Result'); outro('Happy coding! 🎉'); } ================================================ FILE: packages/create-qwik/src/helpers/resolveRelativeDir.ts ================================================ import { resolve } from 'path'; import os from 'node:os'; export function resolveRelativeDir(dir: string) { // check if the outDir start with home ~ if (dir.startsWith('~/')) { return resolve(os.homedir(), dir); } else { return resolve(process.cwd(), dir); } } ================================================ FILE: packages/create-qwik/src/helpers/templateManager.ts ================================================ import type { IntegrationData, IntegrationType } from 'packages/qwik/src/cli/types'; import { loadIntegrations } from 'packages/qwik/src/cli/utils/integrations'; let integrations: IntegrationData[] | undefined = undefined; const LIBRARY_ID = 'library'; const BASE_ID = 'base'; class AppNotFoundError extends Error { constructor(id: string, templates: IntegrationData[]) { super(); this.message = `Invalid app id "${id}". It can only be one of${templates.map( (app) => ` "${app.id}"` )}.`; } } export const makeTemplateManager = async (type: IntegrationType) => { if (!integrations) { integrations = await loadIntegrations(); } const templates = integrations.filter((i) => i.type === type); const standaloneTemplates = templates.filter((i) => i.id !== BASE_ID); function getAppById( id: string, isStandaloneInstallable: boolean = true ): IntegrationData | undefined { if (isStandaloneInstallable) { return standaloneTemplates.find((t) => t.id === id); } return templates.find((t) => t.id === id); } function getBaseApp(): IntegrationData | undefined { return getAppById(BASE_ID, false); } function getBootstrapApps(id: string): { baseApp: IntegrationData; starterApp?: IntegrationData; } { const isLibrary = id === LIBRARY_ID; if (isLibrary) { const libApp = getAppById(id); if (!libApp) { throw new AppNotFoundError(id, standaloneTemplates); } return { baseApp: libApp }; } const baseApp = getAppById(BASE_ID, false); const starterApp = getAppById(id); if (!baseApp) { throw new AppNotFoundError(BASE_ID, standaloneTemplates); } if (!starterApp) { throw new AppNotFoundError(id, standaloneTemplates); } return { baseApp, starterApp }; } return { templates, standaloneTemplates, getAppById, getBootstrapApps, getBaseApp, }; }; export type TemplateManager = Awaited>; ================================================ FILE: packages/create-qwik/src/run-create-cli.ts ================================================ import { cancel, intro, log, spinner as spinnerPrompt } from '@clack/prompts'; import type { CreateAppResult } from 'packages/qwik/src/cli/types'; import { bgBlue } from 'kleur/colors'; import { clearDir } from './helpers/clearDir'; import { createApp } from './create-app'; import fs from 'node:fs'; import { getPackageManager } from '../../qwik/src/cli/utils/utils'; import { installDepsCli } from './helpers/installDepsCli'; import { installDeps as installDepsFn } from 'packages/qwik/src/cli/utils/install-deps'; import { logAppCreated } from './helpers/logAppCreated'; import { makeTemplateManager } from './helpers/templateManager'; import { resolveRelativeDir } from './helpers/resolveRelativeDir'; import yargs from 'yargs'; type Args = { outDir: string; template: string; installDeps: boolean; force: boolean; }; function parseArgs(args: string[], templates: string[]) { const parsedArgs = yargs(args) .strict() .command('*