Skip to content

Commit

Permalink
feat: add Qwik integration (#11068)
Browse files Browse the repository at this point in the history
* feat: add Qwik integration

* feat: add Qwik explanation

* feat: add Qwik dev application

* feat: add secret auto detaction

* feat: add fillOptionsWithEnvVariables method

* refactor: remove @auth/core dependency from the Qwik dev app

* feat: imporve code

* chore: update vite config

* chore: linter 🧽

* suggestions

* suggestions

* fixes

* more suggestions

* callbackUrl -> redirectTo

---------

Co-authored-by: Balázs Orbán <info@balazsorban.com>
  • Loading branch information
gioboa and balazsorban44 committed Jun 19, 2024
1 parent af246b7 commit a9e51ac
Show file tree
Hide file tree
Showing 27 changed files with 2,358 additions and 96 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ packages/*/lib
packages/**/generated
.xata*

# Qwik needs to use .mjs. REVIEW: Check back, can we just use .js?
packages/*/*.mjs

# Development app
apps/dev/src/css
apps/dev/prisma/migrations
Expand Down
4 changes: 4 additions & 0 deletions apps/dev/qwik/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
AUTH_SECRET=

AUTH_GITHUB_ID=
AUTH_GITHUB_SECRET=
41 changes: 41 additions & 0 deletions apps/dev/qwik/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Build
/dist
/lib
/lib-types
/server

# Development
node_modules
*.local

# Cache
.cache
.mf
.rollup.cache
tsconfig.tsbuildinfo

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

# Editor
.vscode/*
!.vscode/launch.json
!.vscode/*.code-snippets

.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?

# Yarn
.yarn/*
!.yarn/releases
65 changes: 65 additions & 0 deletions apps/dev/qwik/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# Qwik City App ⚡️

- [Qwik Docs](https://qwik.dev/)
- [Discord](https://qwik.dev/chat)
- [Qwik GitHub](https://github.com/QwikDev/qwik)
- [@QwikDev](https://twitter.com/QwikDev)
- [Vite](https://vitejs.dev/)

---

## Project Structure

This project is using Qwik with [QwikCity](https://qwik.dev/qwikcity/overview/). QwikCity is just an extra set of tools on top of Qwik to make it easier to build a full site, including directory-based routing, layouts, and more.

Inside your project, you'll see the following directory structure:

```
├── public/
│ └── ...
└── src/
├── components/
│ └── ...
└── routes/
└── ...
```

- `src/routes`: Provides the directory-based routing, which can include a hierarchy of `layout.tsx` layout files, and an `index.tsx` file as the page. Additionally, `index.ts` files are endpoints. Please see the [routing docs](https://qwik.dev/qwikcity/routing/overview/) for more info.

- `src/components`: Recommended directory for components.

- `public`: Any static assets, like images, can be placed in the public directory. Please see the [Vite public directory](https://vitejs.dev/guide/assets.html#the-public-directory) for more info.

## Add Integrations and deployment

Use the `pnpm qwik add` command to add additional integrations. Some examples of integrations includes: Cloudflare, Netlify or Express Server, and the [Static Site Generator (SSG)](https://qwik.dev/qwikcity/guides/static-site-generation/).

```shell
pnpm qwik add # or `pnpm qwik add`
```

## Development

Development mode uses [Vite's development server](https://vitejs.dev/). The `dev` command will server-side render (SSR) the output during development.

```shell
npm start # or `pnpm start`
```

> Note: during dev mode, Vite may request a significant number of `.js` files. This does not represent a Qwik production build.
## Preview

The preview command will create a production build of the client modules, a production build of `src/entry.preview.tsx`, and run a local server. The preview server is only for convenience to preview a production build locally and should not be used as a production server.

```shell
pnpm preview # or `pnpm preview`
```

## Production

The production build will generate client and server modules by running both client and server build commands. The build command will use Typescript to run a type check on the source code.

```shell
pnpm build # or `pnpm build`
```
44 changes: 44 additions & 0 deletions apps/dev/qwik/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
{
"name": "qwik-auth-app",
"description": "Qwik + Auth.js Developer app",
"engines": {
"node": "^18.17.0 || ^20.3.0 || >=21.0.0"
},
"engines-annotation": "Mostly required by sharp which needs a Node-API v9 compatible runtime",
"private": true,
"trustedDependencies": [
"sharp"
],
"trustedDependencies-annotation": "Needed for bun to allow running install scripts",
"type": "module",
"scripts": {
"build": "qwik build",
"build.client": "vite build",
"build.preview": "vite build --ssr src/entry.preview.tsx",
"build.types": "tsc --incremental --noEmit",
"deploy": "echo 'Run \"npm run qwik add\" to install a server adapter'",
"dev": "vite --mode ssr",
"dev.debug": "node --inspect-brk ./node_modules/vite/bin/vite.js --mode ssr --force",
"fmt": "prettier --write .",
"fmt.check": "prettier --check .",
"preview": "qwik build preview && vite preview --open",
"start": "vite --open --mode ssr",
"qwik": "qwik"
},
"devDependencies": {
"@auth/qwik": "workspace:*",
"@builder.io/qwik": "^1.5.5",
"@builder.io/qwik-city": "^1.5.5",
"@types/eslint": "^8.56.10",
"@types/node": "^20.12.7",
"@typescript-eslint/eslint-plugin": "^7.7.1",
"@typescript-eslint/parser": "^7.7.1",
"eslint": "^8.57.0",
"eslint-plugin-qwik": "^1.5.5",
"prettier": "^3.2.5",
"typescript": "5.4.5",
"undici": "*",
"vite": "^5.2.10",
"vite-tsconfig-paths": "^4.2.1"
}
}
1 change: 1 addition & 0 deletions apps/dev/qwik/public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions apps/dev/qwik/public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "https://json.schemastore.org/web-manifest-combined.json",
"name": "qwik-project-name",
"short_name": "Welcome to Qwik",
"start_url": ".",
"display": "standalone",
"background_color": "#fff",
"description": "A Qwik project app."
}
Empty file added apps/dev/qwik/public/robots.txt
Empty file.
4 changes: 4 additions & 0 deletions apps/dev/qwik/qwik.env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
// This file can be used to add references for global types like `vite/client`.

// Add global `vite/client` types. For more info, see: https://vitejs.dev/guide/features#client-types
/// <reference types="vite/client" />
48 changes: 48 additions & 0 deletions apps/dev/qwik/src/components/router-head/router-head.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { component$ } from "@builder.io/qwik"
import { useDocumentHead, useLocation } from "@builder.io/qwik-city"

/**
* The RouterHead component is placed inside of the document `<head>` element.
*/
export const RouterHead = component$(() => {
const head = useDocumentHead()
const loc = useLocation()

return (
<>
<title>{head.title}</title>

<link rel="canonical" href={loc.url.href} />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" type="image/svg+xml" href="/favicon.svg" />

{head.meta.map((m) => (
<meta key={m.key} {...m} />
))}

{head.links.map((l) => (
<link key={l.key} {...l} />
))}

{head.styles.map((s) => (
<style
key={s.key}
{...s.props}
{...(s.props?.dangerouslySetInnerHTML
? {}
: { dangerouslySetInnerHTML: s.style })}
/>
))}

{head.scripts.map((s) => (
<script
key={s.key}
{...s.props}
{...(s.props?.dangerouslySetInnerHTML
? {}
: { dangerouslySetInnerHTML: s.script })}
/>
))}
</>
)
})
17 changes: 17 additions & 0 deletions apps/dev/qwik/src/entry.dev.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* 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, <Root />, opts)
}
21 changes: 21 additions & 0 deletions apps/dev/qwik/src/entry.preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* 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 })
33 changes: 33 additions & 0 deletions apps/dev/qwik/src/entry.ssr.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* 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(<Root />, {
manifest,
...opts,
// Use container attributes to set attributes on the html tag.
containerAttributes: {
lang: "en-us",
...opts.containerAttributes,
},
serverData: {
...opts.serverData,
},
})
}
Empty file added apps/dev/qwik/src/global.css
Empty file.
32 changes: 32 additions & 0 deletions apps/dev/qwik/src/root.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { component$ } from "@builder.io/qwik"
import {
QwikCityProvider,
RouterOutlet,
ServiceWorkerRegister,
} from "@builder.io/qwik-city"
import { RouterHead } from "./components/router-head/router-head"

import "./global.css"

export default component$(() => {
/**
* The root of a QwikCity site always start with the <QwikCityProvider> component,
* immediately followed by the document's <head> and <body>.
*
* Don't remove the `<head>` and `<body>` elements.
*/

return (
<QwikCityProvider>
<head>
<meta charSet="utf-8" />
<link rel="manifest" href="/manifest.json" />
<RouterHead />
</head>
<body lang="en">
<RouterOutlet />
<ServiceWorkerRegister />
</body>
</QwikCityProvider>
)
})
34 changes: 34 additions & 0 deletions apps/dev/qwik/src/routes/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { component$ } from "@builder.io/qwik"
import { Form, type RequestHandler } from "@builder.io/qwik-city"
import { useSession, useSignIn, useSignOut } from "./plugin@auth"

export const onRequest: RequestHandler = (event) => {
const session = event.sharedMap.get("session")
if (!session || new Date(session.expires) < new Date()) {
console.log("Not authorized. Redirect or throw error here.")
}
}

export default component$(() => {
const signIn = useSignIn()
const signOut = useSignOut()
const session = useSession()
return (
<>
<Form action={signIn}>
<input type="hidden" name="providerId" value="github" />
<input
type="hidden"
name="options.callbackUrl"
value="http://qwik-auth-example.com/dashboard"
/>
<button>Sign In</button>
</Form>
Session: {JSON.stringify(session.value)}
<br />
<button onClick$={() => signOut.submit({ callbackUrl: "/" })}>
Sign Out
</button>
</>
)
})
17 changes: 17 additions & 0 deletions apps/dev/qwik/src/routes/layout.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { component$, Slot } from "@builder.io/qwik"
import type { RequestHandler } from "@builder.io/qwik-city"

export const onGet: RequestHandler = async ({ cacheControl }) => {
// Control caching for this request for best performance and to reduce hosting costs:
// https://qwik.dev/docs/caching/
cacheControl({
// Always serve a cached response by default, up to a week stale
staleWhileRevalidate: 60 * 60 * 24 * 7,
// Max once every 5 seconds, revalidate on the server to get a fresh version of this page
maxAge: 5,
})
}

export default component$(() => {
return <Slot />
})
Loading

0 comments on commit a9e51ac

Please sign in to comment.