create-qwik 0.0.37 → 0.0.39-dev20220801194759

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/package.json +1 -1
  2. package/starters/apps/base/{.eslintrc.js → .eslintrc.cjs} +0 -0
  3. package/starters/apps/base/package.json +8 -7
  4. package/starters/apps/base/src/entry.dev.tsx +4 -2
  5. package/starters/apps/base/src/entry.ssr.tsx +3 -3
  6. package/starters/apps/blank/package.json +1 -0
  7. package/starters/apps/blank/src/entry.express.tsx +8 -2
  8. package/starters/apps/blank/src/entry.ssr.tsx +3 -3
  9. package/starters/apps/library/package.json +1 -0
  10. package/starters/apps/qwik-city/package.json +2 -1
  11. package/starters/apps/qwik-city/src/components/breadcrumbs/breadcrumbs.css +25 -0
  12. package/starters/apps/qwik-city/src/components/breadcrumbs/breadcrumbs.tsx +77 -0
  13. package/starters/apps/qwik-city/src/components/footer/footer.css +1 -1
  14. package/starters/apps/qwik-city/src/components/footer/footer.tsx +3 -1
  15. package/starters/apps/qwik-city/src/components/header/header.css +10 -1
  16. package/starters/apps/qwik-city/src/components/header/header.tsx +24 -32
  17. package/starters/apps/qwik-city/src/components/menu/menu.css +10 -0
  18. package/starters/apps/qwik-city/src/components/menu/menu.tsx +4 -4
  19. package/starters/apps/qwik-city/src/global.css +21 -12
  20. package/starters/apps/qwik-city/src/root.tsx +1 -1
  21. package/starters/apps/qwik-city/src/routes/about-us.tsx +2 -4
  22. package/starters/apps/qwik-city/src/routes/api/[org]/[user].json/index.ts +12 -23
  23. package/starters/apps/qwik-city/src/routes/api/_layout-foo/index.tsx +16 -22
  24. package/starters/apps/qwik-city/src/routes/api/data.json.ts +6 -9
  25. package/starters/apps/qwik-city/src/routes/api/index@foo.tsx +7 -4
  26. package/starters/apps/qwik-city/src/routes/blog/[...slug].tsx +28 -5
  27. package/starters/apps/qwik-city/src/routes/blog/_layout/index.tsx +2 -2
  28. package/starters/apps/qwik-city/src/routes/dashboard/index.tsx +8 -0
  29. package/starters/apps/qwik-city/src/routes/docs/[category]/[id]/index.tsx +14 -6
  30. package/starters/apps/qwik-city/src/routes/docs/{_layout/docs.css → _layout!/index.css} +2 -1
  31. package/starters/apps/qwik-city/src/routes/docs/_layout!/index.tsx +31 -0
  32. package/starters/apps/qwik-city/src/routes/docs/_menu.md +4 -2
  33. package/starters/apps/qwik-city/src/routes/docs/getting-started.md +44 -0
  34. package/starters/apps/qwik-city/src/routes/docs/index.tsx +2 -4
  35. package/starters/apps/qwik-city/src/routes/docs/{introduction → overview}/index.md +2 -2
  36. package/starters/apps/qwik-city/src/routes/index.tsx +6 -1
  37. package/starters/apps/qwik-city/src/routes/products/[id].tsx +132 -0
  38. package/starters/features/react/package.json +1 -1
  39. package/starters/features/react/src/entry.ssr.tsx +1 -1
  40. package/starters/features/tailwindcss/{postcss.config.js → postcss.config.cjs} +0 -0
  41. package/starters/features/tailwindcss/{tailwind.config.js → tailwind.config.cjs} +0 -0
  42. package/starters/servers/cloudflare-pages/src/entry.cloudflare.tsx +1 -1
  43. package/starters/servers/express/package.json +1 -1
  44. package/starters/servers/express/src/entry.express.tsx +1 -1
  45. package/starters/servers/netlify/src/entry.netlify.ts +1 -1
  46. package/starters/apps/qwik-city/src/routes/__auth/_layout.tsx +0 -17
  47. package/starters/apps/qwik-city/src/routes/__auth/sign-in.tsx +0 -25
  48. package/starters/apps/qwik-city/src/routes/__auth/sign-up.tsx +0 -29
  49. package/starters/apps/qwik-city/src/routes/docs/_layout/index.tsx +0 -23
  50. package/starters/apps/qwik-city/src/routes/docs/getting-started.mdx +0 -32
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-qwik",
3
- "version": "0.0.37",
3
+ "version": "0.0.39-dev20220801194759",
4
4
  "description": "Interactive CLI and API for generating Qwik projects.",
5
5
  "bin": "create-qwik",
6
6
  "main": "index.js",
@@ -9,23 +9,24 @@
9
9
  "dev": "npm run dev.ssr",
10
10
  "dev.client": "vite",
11
11
  "dev.ssr": "node --inspect node_modules/vite/bin/vite.js --mode ssr",
12
- "dev.debug": "node --inspect-brk node_modules/vite/bin/vite.js --mode ssr",
12
+ "dev.debug": "node --inspect-brk node_modules/vite/bin/vite.js --force --mode ssr",
13
13
  "start": "npm run dev",
14
14
  "lint": "eslint \"src/**/*.ts*\"",
15
15
  "typecheck": "tsc --incremental --noEmit"
16
16
  },
17
17
  "devDependencies": {
18
- "@builder.io/qwik": "0.0.37",
18
+ "@builder.io/qwik": "0.0.39-dev20220801194759",
19
19
  "@types/eslint": "8.4.5",
20
20
  "@types/node": "latest",
21
- "@typescript-eslint/eslint-plugin": "5.30.6",
22
- "@typescript-eslint/parser": "5.30.6",
23
- "eslint-plugin-qwik": "0.0.37",
21
+ "@typescript-eslint/eslint-plugin": "5.30.7",
22
+ "@typescript-eslint/parser": "5.30.7",
23
+ "eslint-plugin-qwik": "0.0.39-dev20220801194759",
24
24
  "eslint": "8.20.0",
25
- "node-fetch": "3.2.8",
25
+ "node-fetch": "3.2.9",
26
26
  "typescript": "4.7.4",
27
- "vite": "3.0.1"
27
+ "vite": "3.0.2"
28
28
  },
29
+ "type": "module",
29
30
  "homepage": "https://qwik.builder.io/",
30
31
  "private": true,
31
32
  "engines": {
@@ -1,4 +1,4 @@
1
- import { render } from '@builder.io/qwik';
1
+ import { render, RenderOptions } from '@builder.io/qwik';
2
2
  import Root from './root';
3
3
 
4
4
  /**
@@ -10,4 +10,6 @@ import Root from './root';
10
10
  * - More code is transferred to the browser than in SSR mode.
11
11
  * - Optimizer/Serialization/Deserialization code is not exercised!
12
12
  */
13
- render(document, <Root />);
13
+ export default function (opts: RenderOptions) {
14
+ return render(document, <Root />, opts);
15
+ }
@@ -1,14 +1,14 @@
1
- import { renderToString, RenderOptions } from '@builder.io/qwik/server';
1
+ import { renderToStream, RenderToStreamOptions } from '@builder.io/qwik/server';
2
2
  import { manifest } from '@qwik-client-manifest';
3
3
  import Root from './root';
4
4
 
5
5
  /**
6
6
  * Server-Side Render method to be called by a server.
7
7
  */
8
- export function render(opts?: RenderOptions) {
8
+ export default function (opts: RenderToStreamOptions) {
9
9
  // Render the Root component to a string
10
10
  // Pass in the manifest that was generated from the client build
11
- return renderToString(<Root />, {
11
+ return renderToStream(<Root />, {
12
12
  manifest,
13
13
  ...opts,
14
14
  });
@@ -8,6 +8,7 @@
8
8
  "@types/express": "4.17.13",
9
9
  "express": "4.17.3"
10
10
  },
11
+ "type": "module",
11
12
  "__qwik__": {
12
13
  "priority": 0,
13
14
  "featureOptions": [
@@ -1,6 +1,9 @@
1
1
  import express from 'express';
2
2
  import { join } from 'path';
3
- import { render } from './entry.ssr';
3
+ import { fileURLToPath } from 'url';
4
+ import render from './entry.ssr';
5
+
6
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
4
7
 
5
8
  /**
6
9
  * Create an express server
@@ -32,11 +35,14 @@ app.get('/*', async (req, res, next) => {
32
35
  try {
33
36
  // Render the Root component to a string
34
37
  const result = await render({
38
+ stream: res,
35
39
  url: req.url,
36
40
  });
37
41
 
38
42
  // respond with SSR'd HTML
39
- res.send(result.html);
43
+ if ('html' in result) {
44
+ res.send((result as any).html);
45
+ }
40
46
  } catch (e) {
41
47
  // Error while server-side rendering
42
48
  next(e);
@@ -1,14 +1,14 @@
1
- import { renderToString, RenderOptions } from '@builder.io/qwik/server';
1
+ import { renderToStream, RenderToStreamOptions } from '@builder.io/qwik/server';
2
2
  import { manifest } from '@qwik-client-manifest';
3
3
  import Root from './root';
4
4
 
5
5
  /**
6
6
  * Server-Side Render method to be called by a server.
7
7
  */
8
- export function render(opts?: RenderOptions) {
8
+ export default function (opts: RenderToStreamOptions) {
9
9
  // Render the Root component to a string
10
10
  // Pass in the manifest that was generated from the client build
11
- return renderToString(<Root />, {
11
+ return renderToStream(<Root />, {
12
12
  manifest,
13
13
  ...opts,
14
14
  });
@@ -6,6 +6,7 @@
6
6
  "qwik": "./lib/index.qwik.mjs",
7
7
  "module": "./lib/index.qwik.mjs",
8
8
  "types": "./lib/types/index.d.ts",
9
+ "type": "module",
9
10
  "exports": {
10
11
  ".": {
11
12
  "import": "./lib/index.qwik.mjs",
@@ -12,8 +12,9 @@
12
12
  "prettier"
13
13
  ]
14
14
  },
15
+ "type": "module",
15
16
  "devDependencies": {
16
- "@builder.io/qwik-city": "0.0.20",
17
+ "@builder.io/qwik-city": "0.0.26",
17
18
  "vite-tsconfig-paths": "3.5.0"
18
19
  }
19
20
  }
@@ -0,0 +1,25 @@
1
+ nav.breadcrumbs {
2
+ padding: 5px;
3
+ border-bottom: 1px solid #ddd;
4
+ }
5
+
6
+ nav.breadcrumbs > span {
7
+ display: inline-block;
8
+ padding: 5px 0;
9
+ font-size: 12px;
10
+ }
11
+
12
+ nav.breadcrumbs > span a {
13
+ text-decoration: none;
14
+ color: inherit;
15
+ }
16
+
17
+ nav.breadcrumbs > span::after {
18
+ content: '>';
19
+ padding: 0 5px;
20
+ opacity: 0.4;
21
+ }
22
+
23
+ nav.breadcrumbs > span:last-child::after {
24
+ display: none;
25
+ }
@@ -0,0 +1,77 @@
1
+ import { component$, Host, useScopedStyles$ } from '@builder.io/qwik';
2
+ import { useContent, useLocation, ContentMenu } from '@builder.io/qwik-city';
3
+ import styles from './breadcrumbs.css?inline';
4
+
5
+ export const Breadcrumbs = component$(
6
+ () => {
7
+ useScopedStyles$(styles);
8
+
9
+ const { menu } = useContent();
10
+ const loc = useLocation();
11
+
12
+ const breadcrumbs = createBreadcrumbs(menu, loc.pathname);
13
+ if (breadcrumbs.length === 0) {
14
+ return null;
15
+ }
16
+
17
+ return (
18
+ <Host class="breadcrumbs">
19
+ {breadcrumbs.map((b) => (
20
+ <span>{b.href ? <a href={b.href}>{b.text}</a> : b.text}</span>
21
+ ))}
22
+ </Host>
23
+ );
24
+ },
25
+ { tagName: 'nav' }
26
+ );
27
+
28
+ export function createBreadcrumbs(menu: ContentMenu | undefined, pathname: string) {
29
+ if (menu?.items) {
30
+ for (const indexA of menu.items) {
31
+ const breadcrumbA: ContentBreadcrumb = {
32
+ text: indexA.text,
33
+ };
34
+ if (typeof indexA.href === 'string') {
35
+ breadcrumbA.href = indexA.href;
36
+ }
37
+ if (indexA.href === pathname) {
38
+ return [breadcrumbA];
39
+ }
40
+
41
+ if (indexA.items) {
42
+ for (const indexB of indexA.items) {
43
+ const breadcrumbB: ContentBreadcrumb = {
44
+ text: indexB.text,
45
+ };
46
+ if (typeof indexB.href === 'string') {
47
+ breadcrumbB.href = indexB.href;
48
+ }
49
+ if (indexB.href === pathname) {
50
+ return [breadcrumbA, breadcrumbB];
51
+ }
52
+
53
+ if (indexB.items) {
54
+ for (const indexC of indexB.items) {
55
+ const breadcrumbC: ContentBreadcrumb = {
56
+ text: indexC.text,
57
+ };
58
+ if (typeof indexC.href === 'string') {
59
+ breadcrumbC.href = indexC.href;
60
+ }
61
+ if (indexC.href === pathname) {
62
+ return [breadcrumbA, breadcrumbB, breadcrumbC];
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
+ }
69
+ }
70
+
71
+ return [];
72
+ }
73
+
74
+ interface ContentBreadcrumb {
75
+ text: string;
76
+ href?: string;
77
+ }
@@ -1,5 +1,5 @@
1
1
  footer {
2
- border-top: 1px solid #949494;
2
+ border-top: 1px solid #ddd;
3
3
  margin-top: 40px;
4
4
  padding: 20px;
5
5
  }
@@ -21,7 +21,9 @@ export default component$(
21
21
  <a href="/sign-in">Sign In</a>
22
22
  </li>
23
23
  <li>
24
- <a href="/">Home</a>
24
+ <a class="footer-home" href="/">
25
+ Home
26
+ </a>
25
27
  </li>
26
28
  </ul>
27
29
  </Host>
@@ -1,8 +1,17 @@
1
1
  header {
2
+ background-color: #0093ee;
3
+ }
4
+
5
+ header .header-inner {
2
6
  display: grid;
3
7
  grid-template-columns: 1fr auto auto;
4
8
  padding: 10px;
5
- background-color: #0093ee;
9
+ max-width: 800px;
10
+ margin: 0 auto;
11
+ }
12
+
13
+ .full-screen header .header-inner {
14
+ max-width: 100%;
6
15
  }
7
16
 
8
17
  header a {
@@ -3,43 +3,35 @@ import { useLocation } from '@builder.io/qwik-city';
3
3
  import styles from './header.css?inline';
4
4
 
5
5
  export default component$(
6
- (props: { fullWidth?: boolean }) => {
6
+ () => {
7
7
  useStyles$(styles);
8
8
 
9
9
  const pathname = useLocation().pathname;
10
10
 
11
11
  return (
12
- <Host class={{ 'full-width': !!props.fullWidth }}>
13
- <section>
14
- <a href="/">Qwik City 🏙</a>
15
- </section>
16
- <nav>
17
- <a href="/blog" class={{ active: pathname === '/blog' }}>
18
- Blog
19
- </a>
20
- <a href="/docs" class={{ active: pathname === '/docs' }}>
21
- Docs
22
- </a>
23
- <a href="/api" class={{ active: pathname === '/api' }}>
24
- API
25
- </a>
26
- <a href="/about-us" class={{ active: pathname === '/about-us' }}>
27
- About Us
28
- </a>
29
- <a href="/sign-in" class={{ active: pathname === '/sign-in' }}>
30
- Sign In
31
- </a>
32
- </nav>
33
- {/* <button
34
- class="theme-toggle"
35
- onClick$={() => {
36
- if (themeCtx.theme === 'light') {
37
- themeCtx.theme = 'dark';
38
- } else {
39
- themeCtx.theme = 'light';
40
- }
41
- }}
42
- /> */}
12
+ <Host>
13
+ <div class="header-inner">
14
+ <section class="logo">
15
+ <a href="/">Qwik City 🏙</a>
16
+ </section>
17
+ <nav>
18
+ <a href="/blog" class={{ active: pathname.startsWith('/blog') }}>
19
+ Blog
20
+ </a>
21
+ <a href="/docs" class={{ active: pathname.startsWith('/docs') }}>
22
+ Docs
23
+ </a>
24
+ <a href="/api" class={{ active: pathname.startsWith('/api') }}>
25
+ API
26
+ </a>
27
+ <a href="/products/hat" class={{ active: pathname.startsWith('/products') }}>
28
+ Products
29
+ </a>
30
+ <a href="/about-us" class={{ active: pathname.startsWith('/about-us') }}>
31
+ About Us
32
+ </a>
33
+ </nav>
34
+ </div>
43
35
  </Host>
44
36
  );
45
37
  },
@@ -1,3 +1,13 @@
1
1
  .menu {
2
2
  background: #eee;
3
+ padding: 20px 10px;
4
+ }
5
+
6
+ .menu h5 {
7
+ margin: 0;
8
+ }
9
+
10
+ .menu ul {
11
+ padding-left: 20px;
12
+ margin: 5px 0 25px 0;
3
13
  }
@@ -1,12 +1,12 @@
1
1
  import { component$, Host, useScopedStyles$ } from '@builder.io/qwik';
2
- import { useContentMenu, useLocation } from '@builder.io/qwik-city';
2
+ import { useContent, Link, useLocation } from '@builder.io/qwik-city';
3
3
  import styles from './menu.css?inline';
4
4
 
5
5
  export const Menu = component$(
6
6
  () => {
7
7
  useScopedStyles$(styles);
8
8
 
9
- const menu = useContentMenu();
9
+ const { menu } = useContent();
10
10
  const loc = useLocation();
11
11
 
12
12
  return (
@@ -18,14 +18,14 @@ export const Menu = component$(
18
18
  <ul>
19
19
  {item.items?.map((item) => (
20
20
  <li>
21
- <a
21
+ <Link
22
22
  href={item.href}
23
23
  class={{
24
24
  'is-active': loc.pathname === item.href,
25
25
  }}
26
26
  >
27
27
  {item.text}
28
- </a>
28
+ </Link>
29
29
  </li>
30
30
  ))}
31
31
  </ul>
@@ -1,15 +1,24 @@
1
- html {
2
- line-height: 1.5;
3
- -webkit-text-size-adjust: 100%;
4
- -moz-tab-size: 4;
5
- -o-tab-size: 4;
6
- tab-size: 4;
7
- font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
8
- 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji',
9
- 'Segoe UI Symbol', 'Noto Color Emoji';
10
- }
11
-
12
1
  body {
2
+ margin: 0;
13
3
  padding: 0;
14
- line-height: inherit;
4
+ font-family: system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue',
5
+ sans-serif;
6
+ }
7
+
8
+ main {
9
+ padding: 10px 20px;
10
+ max-width: 800px;
11
+ margin: 0 auto;
12
+ }
13
+
14
+ .full-screen main {
15
+ max-width: 100%;
16
+ }
17
+
18
+ a {
19
+ color: #006eb3;
20
+ }
21
+
22
+ a:hover {
23
+ text-decoration: none;
15
24
  }
@@ -6,7 +6,7 @@ import './global.css';
6
6
 
7
7
  export default () => {
8
8
  return (
9
- <Html lang="en">
9
+ <Html lang="en" dir="ltr">
10
10
  <Head />
11
11
  <Body />
12
12
  </Html>
@@ -12,8 +12,6 @@ export default component$(() => {
12
12
  );
13
13
  });
14
14
 
15
- export const head: DocumentHead = () => {
16
- return {
17
- title: 'About US',
18
- };
15
+ export const head: DocumentHead = {
16
+ title: 'About Us',
19
17
  };
@@ -3,30 +3,19 @@ import os from 'os';
3
3
 
4
4
  export const onGet: EndpointHandler = ({ request, params }) => {
5
5
  return {
6
- status: 200,
7
- body: {
8
- timestamp: Date.now(),
9
- method: request.method,
10
- url: request.url,
11
- params,
12
- os: os.platform(),
13
- arch: os.arch(),
14
- node: process.versions.node,
15
- },
6
+ timestamp: Date.now(),
7
+ method: request.method,
8
+ url: request.url,
9
+ params,
10
+ os: os.platform(),
11
+ arch: os.arch(),
12
+ node: process.versions.node,
16
13
  };
17
14
  };
18
15
 
19
- export const onPost: EndpointHandler = async ({ request, params }) => {
20
- return {
21
- status: 200,
22
- body: {
23
- timestamp: Date.now(),
24
- method: request.method,
25
- url: request.url,
26
- params,
27
- os: os.platform(),
28
- arch: os.arch(),
29
- node: process.versions.node,
30
- },
31
- };
16
+ export const onPost: EndpointHandler = async ({ request, response }) => {
17
+ response.headers.set('Content-Type', 'text/plain');
18
+ return `Platform: ${os.platform()}, Node: ${process.versions.node}, HTTP Method: ${
19
+ request.method
20
+ }`;
32
21
  };
@@ -1,38 +1,32 @@
1
1
  import { component$, Host, Slot, useScopedStyles$ } from '@builder.io/qwik';
2
2
  import type { DocumentHead } from '@builder.io/qwik-city';
3
- import Footer from '../../../components/footer/footer';
4
- import Header from '../../../components/header/header';
5
3
  import styles from './api.css?inline';
6
4
 
7
5
  export default component$(() => {
8
6
  useScopedStyles$(styles);
9
7
 
10
8
  return (
11
- <Host>
12
- <Header fullWidth={true} />
13
- <main class="api">
14
- <aside class="api-menu">
15
- <h2>API</h2>
16
- <ul>
17
- <li>
18
- <a href="/api/builder.io/oss.json">Org/User</a>
19
- </li>
20
- <li>
21
- <a href="/api/data.json">Data</a>
22
- </li>
23
- </ul>
24
- </aside>
25
- <section class="api-content">
26
- <Slot />
27
- </section>
28
- </main>
29
- <Footer />
9
+ <Host class="api">
10
+ <aside class="api-menu">
11
+ <h2>API</h2>
12
+ <ul>
13
+ <li>
14
+ <a href="/api/builder.io/oss.json">Org/User</a>
15
+ </li>
16
+ <li>
17
+ <a href="/api/data.json">Data</a>
18
+ </li>
19
+ </ul>
20
+ </aside>
21
+ <section class="api-content">
22
+ <Slot />
23
+ </section>
30
24
  </Host>
31
25
  );
32
26
  });
33
27
 
34
28
  export const head: DocumentHead = ({ pathname }) => {
35
29
  return {
36
- title: pathname,
30
+ title: `API: ${pathname}`,
37
31
  };
38
32
  };
@@ -3,14 +3,11 @@ import os from 'os';
3
3
 
4
4
  export const onGet: EndpointHandler = ({ request }) => {
5
5
  return {
6
- status: 200,
7
- body: {
8
- timestamp: Date.now(),
9
- method: request.method,
10
- url: request.url,
11
- os: os.platform(),
12
- arch: os.arch(),
13
- node: process.versions.node,
14
- },
6
+ timestamp: Date.now(),
7
+ method: request.method,
8
+ url: request.url,
9
+ os: os.platform(),
10
+ arch: os.arch(),
11
+ node: process.versions.node,
15
12
  };
16
13
  };
@@ -1,7 +1,7 @@
1
1
  import { component$, Host, useClientEffect$, useStore } from '@builder.io/qwik';
2
2
 
3
3
  export default component$(() => {
4
- const store = useStore({ timestamp: 0, os: '', arch: '', node: '' });
4
+ const store = useStore({ timestamp: '', os: '', arch: '', node: '' });
5
5
 
6
6
  useClientEffect$(async () => {
7
7
  const url = `/api/builder.io/oss.json`;
@@ -28,9 +28,12 @@ export default component$(() => {
28
28
  </ul>
29
29
 
30
30
  <p>Timestamp: {store.timestamp}</p>
31
- <p>OS: {store.os}</p>
32
- <p>Arch: {store.arch}</p>
33
- <p>Node: {store.node}</p>
31
+ <p>
32
+ Node: <span>{store.node}</span>
33
+ </p>
34
+ <p>
35
+ OS: <span>{store.os}</span>
36
+ </p>
34
37
  </Host>
35
38
  );
36
39
  });
@@ -1,13 +1,36 @@
1
- import { component$, Host } from '@builder.io/qwik';
2
- import { useLocation } from '@builder.io/qwik-city';
1
+ import { component$, Host, Resource } from '@builder.io/qwik';
2
+ import { useEndpoint, DocumentHead, EndpointHandler } from '@builder.io/qwik-city';
3
3
 
4
4
  export default component$(() => {
5
- const { pathname, params } = useLocation();
5
+ const resource = useEndpoint<typeof onGet>();
6
6
 
7
7
  return (
8
8
  <Host>
9
- <h1>Blog {pathname}</h1>
10
- <p>Slug: {params.slug}</p>
9
+ <Resource
10
+ resource={resource}
11
+ onResolved={(blog) => (
12
+ <>
13
+ <h1>{blog.blogTitle}</h1>
14
+ <p>{blog.blogContent}</p>
15
+ </>
16
+ )}
17
+ />
11
18
  </Host>
12
19
  );
13
20
  });
21
+
22
+ export const onGet: EndpointHandler<EndpointData> = async ({ params, request }) => {
23
+ return {
24
+ blogTitle: `Blog: ${params.slug}`,
25
+ blogContent: `${params.slug}, ${request.url}`,
26
+ };
27
+ };
28
+
29
+ export const head: DocumentHead<EndpointData> = ({ data }) => {
30
+ return { title: data?.blogTitle };
31
+ };
32
+
33
+ export interface EndpointData {
34
+ blogTitle: string;
35
+ blogContent: string;
36
+ }
@@ -9,10 +9,10 @@ export default component$(() => {
9
9
  <aside class="blog-menu">
10
10
  <ul>
11
11
  <li>
12
- <a href="/blog/how-to-use-a-toaster">How to use a toaster</a>
12
+ <a href="/blog/what-is-resumability">What Is Resumability?</a>
13
13
  </li>
14
14
  <li>
15
- <a href="/blog/how-to-crack-an-egg">How to crack an egg</a>
15
+ <a href="/blog/serializing-props">Serializing Props</a>
16
16
  </li>
17
17
  </ul>
18
18
  </aside>
@@ -1,9 +1,17 @@
1
1
  import { component$, Host } from '@builder.io/qwik';
2
+ import type { DocumentHead } from '@builder.io/qwik-city';
2
3
 
3
4
  export default component$(() => {
4
5
  return (
5
6
  <Host>
6
7
  <h1>Dashboard</h1>
8
+ <p>
9
+ <a href="/sign-out">Sign Out</a>
10
+ </p>
7
11
  </Host>
8
12
  );
9
13
  });
14
+
15
+ export const head: DocumentHead = {
16
+ title: 'Dashboard',
17
+ };
@@ -1,15 +1,23 @@
1
1
  import { component$, Host } from '@builder.io/qwik';
2
- import { useLocation } from '@builder.io/qwik-city';
2
+ import { useLocation, DocumentHead } from '@builder.io/qwik-city';
3
3
 
4
4
  export default component$(() => {
5
- const loc = useLocation();
5
+ const { pathname, params } = useLocation();
6
6
 
7
7
  return (
8
8
  <Host>
9
- <h1>Docs</h1>
10
- <p>pathname: {loc.pathname}</p>
11
- <p>category: {loc.params.category}</p>
12
- <p>id: {loc.params.id}</p>
9
+ <h1>
10
+ Docs: {params.category} {params.id}
11
+ </h1>
12
+ <p>pathname: {pathname}</p>
13
+ <p>category: {params.category}</p>
14
+ <p>id: {params.id}</p>
13
15
  </Host>
14
16
  );
15
17
  });
18
+
19
+ export const head: DocumentHead = ({ params }) => {
20
+ return {
21
+ title: `${params.category} ${params.id}`,
22
+ };
23
+ };
@@ -1,7 +1,8 @@
1
- .docs {
1
+ .docs main {
2
2
  display: grid;
3
3
  grid-template-columns: 200px 1fr;
4
4
  padding: 0;
5
+ margin: 0;
5
6
  }
6
7
 
7
8
  .docs-content {
@@ -0,0 +1,31 @@
1
+ import { component$, Host, Slot, useStyles$ } from '@builder.io/qwik';
2
+ import type { DocumentHead } from '@builder.io/qwik-city';
3
+ import { Breadcrumbs } from '../../../components/breadcrumbs/breadcrumbs';
4
+ import Footer from '../../../components/footer/footer';
5
+ import Header from '../../../components/header/header';
6
+ import { Menu } from '../../../components/menu/menu';
7
+ import styles from './index.css?inline';
8
+
9
+ export default component$(() => {
10
+ useStyles$(styles);
11
+
12
+ return (
13
+ <Host class="docs full-screen">
14
+ <Header />
15
+ <main>
16
+ <Menu />
17
+ <section class="docs-content">
18
+ <Breadcrumbs />
19
+ <Slot />
20
+ <Footer />
21
+ </section>
22
+ </main>
23
+ </Host>
24
+ );
25
+ });
26
+
27
+ export const head: DocumentHead = ({ head }) => {
28
+ return {
29
+ title: `Docs: ${head.title}`,
30
+ };
31
+ };
@@ -1,9 +1,11 @@
1
1
  # Docs
2
2
 
3
- ## Getting Started
3
+ ## Introduction
4
4
 
5
- - [Introduction](introduction/index.md)
5
+ - [Overview](overview/index.md)
6
+ - [Getting Started](getting-started.md)
6
7
 
7
8
  ## Components
8
9
 
9
10
  - [Basics](/docs/components/basics)
11
+ - [Listeners](/docs/components/listeners)
@@ -0,0 +1,44 @@
1
+ ---
2
+ title: Getting Started
3
+ ---
4
+
5
+ # Getting Started
6
+
7
+ ## Creating an app using the CLI
8
+
9
+ The first step is to create an application. Qwik comes with a CLI that allows you to create a basic working skeleton of an application. We will use the CLI to create a Todo sample app, and we will use that application to do a walk-through of Qwik so that you can familiarize yourself with it.
10
+
11
+ ## Running in development
12
+
13
+ Once the application is download.
14
+
15
+ 1. Change into the directory created by the `npm create qwik@latest`.
16
+
17
+ ```shell
18
+ cd qwik-todo
19
+ ```
20
+
21
+ 2. Install NPM modules:
22
+
23
+ ```shell
24
+ npm install
25
+ ```
26
+
27
+ 3. Invoke the dev server
28
+
29
+ ```shell
30
+ npm start
31
+ ```
32
+
33
+ 4. You should see a server running with your To-do application
34
+
35
+ ```shell
36
+ vite v2.8.6 dev server running at:
37
+
38
+ > Local: http://localhost:3000/
39
+ > Network: use `--host` to expose
40
+
41
+ ready in 157ms.
42
+ ```
43
+
44
+ 5. Visit http://localhost:3000/ to explore the To-do app.
@@ -9,8 +9,6 @@ export default component$(() => {
9
9
  );
10
10
  });
11
11
 
12
- export const head: DocumentHead = () => {
13
- return {
14
- title: 'Welcome!',
15
- };
12
+ export const head: DocumentHead = {
13
+ title: 'Welcome!',
16
14
  };
@@ -1,7 +1,7 @@
1
1
  ---
2
- title: Introduction
2
+ title: Overview
3
3
  ---
4
4
 
5
- # Introduction
5
+ # Overview
6
6
 
7
7
  Qwik is a new kind of web framework that can deliver instant loading web applications at any size or complexity. Your sites and apps can boot with less than 1kb of JS (_including_ your code, regardless of complexity), and achieve unheard of performance at scale.
@@ -1,11 +1,16 @@
1
1
  import { component$, Host } from '@builder.io/qwik';
2
+ import type { DocumentHead } from '@builder.io/qwik-city';
2
3
 
3
4
  export default component$(() => {
4
5
  return (
5
6
  <Host>
6
- <h1>Welcome to QwikCity</h1>
7
+ <h1 onClick$={() => console.warn('hola')}>Welcome to Qwik City</h1>
7
8
 
8
9
  <p>The meta-framework for Qwik.</p>
9
10
  </Host>
10
11
  );
11
12
  });
13
+
14
+ export const head: DocumentHead = {
15
+ title: 'Welcome to Qwik City',
16
+ };
@@ -0,0 +1,132 @@
1
+ import { Resource, component$, Host, useStore } from '@builder.io/qwik';
2
+ import { useEndpoint, useLocation, EndpointHandler, DocumentHead } from '@builder.io/qwik-city';
3
+ import os from 'os';
4
+
5
+ export default component$(() => {
6
+ const { params, pathname } = useLocation();
7
+ const store = useStore({ productFetchData: '' });
8
+
9
+ const resource = useEndpoint<typeof onGet>();
10
+
11
+ return (
12
+ <Host>
13
+ <Resource
14
+ resource={resource}
15
+ onPending={() => <p>Loading</p>}
16
+ onResolved={(product) => {
17
+ if (product == null) {
18
+ return <h1>Product "{params.id}" not found</h1>;
19
+ }
20
+
21
+ return (
22
+ <>
23
+ <h1>Product: {product.productId}</h1>
24
+ <p>Price: {product.price}</p>
25
+ <p>{product.description}</p>
26
+ </>
27
+ );
28
+ }}
29
+ />
30
+
31
+ <p>(Artificial response delay of 250ms)</p>
32
+
33
+ <p>
34
+ <button
35
+ onClick$={async () => {
36
+ const rsp = await fetch(pathname, {
37
+ headers: { accept: 'application/json' },
38
+ });
39
+ store.productFetchData = JSON.stringify(await rsp.json(), null, 2);
40
+ }}
41
+ >
42
+ fetch("{pathname}") data
43
+ </button>
44
+ </p>
45
+
46
+ <pre>
47
+ <code>{store.productFetchData}</code>
48
+ </pre>
49
+
50
+ <hr />
51
+
52
+ <ul>
53
+ <li>
54
+ <a href="/products/jacket">Jacket</a>
55
+ </li>
56
+ <li>
57
+ <a href="/products/hat">Hat</a>
58
+ </li>
59
+ <li>
60
+ <a href="/products/shirt">T-Shirt (Redirect to /products/tshirt)</a>
61
+ </li>
62
+ <li>
63
+ <a href="/products/hoodie">Hoodie (404 Not Found)</a>
64
+ </li>
65
+ </ul>
66
+ </Host>
67
+ );
68
+ });
69
+
70
+ export const head: DocumentHead<ProductData | null> = ({ data }) => {
71
+ if (!data) {
72
+ return {
73
+ title: 'Product Not Found',
74
+ };
75
+ }
76
+
77
+ return {
78
+ title: `Product ${data.productId}, ${data.price}`,
79
+ };
80
+ };
81
+
82
+ export const onGet: EndpointHandler<EndpointData> = async ({ params, response }) => {
83
+ // Serverside Endpoint
84
+ // During SSR, this method is called directly on the server and returns the data object
85
+ // On the client, this same data can be requested with fetch() at the same URL, but also
86
+ // requires the "accept: application/json" request header.
87
+
88
+ // artificial slow response
89
+ await new Promise<void>((resolve) => setTimeout(resolve, 250));
90
+
91
+ if (params.id === 'shirt') {
92
+ // Redirect, which will skip any rendering and the server will immediately redirect
93
+ response.redirect('/products/tshirt');
94
+ return;
95
+ }
96
+
97
+ const productPrice = PRODUCT_DB[params.id];
98
+
99
+ if (!productPrice) {
100
+ // Product data not found
101
+ // but the data is still given to the renderer to decide what to do
102
+ response.status = 404;
103
+ return null;
104
+ }
105
+
106
+ // Found the product data
107
+ // This same data is passed to the head() function
108
+ // and in the component$() it can be access with useEndpoint()
109
+ response.headers.set('Cache-Control', 'no-cache, no-store, no-fun');
110
+ return {
111
+ productId: params.id,
112
+ price: productPrice,
113
+ description: `Node ${process.versions.node} ${os.platform()} ${os.arch()} ${
114
+ os.cpus()[0].model
115
+ }`,
116
+ };
117
+ };
118
+
119
+ // Our pretty awesome database of prices
120
+ const PRODUCT_DB: Record<string, string> = {
121
+ hat: '$21.96',
122
+ jacket: '$48.96',
123
+ tshirt: '$18.96',
124
+ };
125
+
126
+ type EndpointData = ProductData | null;
127
+
128
+ interface ProductData {
129
+ productId: string;
130
+ price: string;
131
+ description: string;
132
+ }
@@ -5,7 +5,7 @@
5
5
  "fmt.check": "prettier --check ."
6
6
  },
7
7
  "devDependencies": {
8
- "@builder.io/qwik-react": "0.0.7",
8
+ "@builder.io/qwik-react": "0.0.8",
9
9
  "@emotion/react": "11.9.3",
10
10
  "@emotion/server": "11.4.0",
11
11
  "@emotion/styled": "11.9.3",
@@ -3,7 +3,7 @@ import { renderToString } from '@builder.io/qwik-react';
3
3
  import { manifest } from '@qwik-client-manifest';
4
4
  import Root from './root';
5
5
 
6
- export function render(opts: RenderOptions) {
6
+ export default function (opts: RenderOptions) {
7
7
  return renderToString(<Root />, {
8
8
  manifest,
9
9
  ...opts,
@@ -1,4 +1,4 @@
1
- import { render } from './entry.ssr';
1
+ import render from './entry.ssr';
2
2
 
3
3
  /**
4
4
  * Cloudflare Pages Request Handler
@@ -2,7 +2,7 @@
2
2
  "description": "Express.js server.",
3
3
  "scripts": {
4
4
  "build.ssr": "vite build --ssr src/entry.express.tsx",
5
- "serve": "node server/entry.express.mjs"
5
+ "serve": "node server/entry.express"
6
6
  },
7
7
  "devDependencies": {
8
8
  "@types/express": "4.17.13",
@@ -3,7 +3,7 @@ import { fileURLToPath } from 'url';
3
3
  import { join } from 'path';
4
4
  import cityPlan from '@qwik-city-plan';
5
5
  import { qwikCity } from '@builder.io/qwik-city/middleware/express';
6
- import { render } from './entry.ssr';
6
+ import render from './entry.ssr';
7
7
 
8
8
  const app = express();
9
9
 
@@ -1,4 +1,4 @@
1
- import { render } from './entry.ssr';
1
+ import render from './entry.ssr';
2
2
 
3
3
  const handler = async (request: Request) => {
4
4
  try {
@@ -1,17 +0,0 @@
1
- import { component$, Host, Slot } from '@builder.io/qwik';
2
-
3
- export default component$(() => {
4
- return (
5
- <Host>
6
- <section>
7
- <Slot />
8
- </section>
9
- <aside>
10
- <p>Account Help</p>
11
- <ul>
12
- <li>Forgot password</li>
13
- </ul>
14
- </aside>
15
- </Host>
16
- );
17
- });
@@ -1,25 +0,0 @@
1
- import { component$, Host } from '@builder.io/qwik';
2
- import type { DocumentHead } from '@builder.io/qwik-city';
3
-
4
- export default component$(() => {
5
- return (
6
- <Host>
7
- <h1>Sign In</h1>
8
- <form action="/api/on-sign-in" method="post">
9
- <label>
10
- <span>Username</span>
11
- <input name="username" type="text" />
12
- </label>
13
- <label>
14
- <span>Password</span>
15
- <input name="password" type="password" />
16
- </label>
17
- <button>Log In</button>
18
- </form>
19
- </Host>
20
- );
21
- });
22
-
23
- export const head: DocumentHead = {
24
- title: 'Sign In',
25
- };
@@ -1,29 +0,0 @@
1
- import { component$, Host } from '@builder.io/qwik';
2
- import type { DocumentHead } from '@builder.io/qwik-city';
3
-
4
- export default component$(() => {
5
- return (
6
- <Host>
7
- <h1>Sign Up</h1>
8
- <form>
9
- <label>
10
- <span>Username</span>
11
- <input type="text" />
12
- </label>
13
- <label>
14
- <span>Password</span>
15
- <input type="password" />
16
- </label>
17
- <label>
18
- <span>Re-entry Password</span>
19
- <input type="password" />
20
- </label>
21
- <button>Create Account</button>
22
- </form>
23
- </Host>
24
- );
25
- });
26
-
27
- export const head: DocumentHead = {
28
- title: 'Sign Up',
29
- };
@@ -1,23 +0,0 @@
1
- import { component$, Host, Slot, useStyles$ } from '@builder.io/qwik';
2
- import type { DocumentHead } from '@builder.io/qwik-city';
3
- import { Menu } from '../../../components/menu/menu';
4
- import styles from './docs.css?inline';
5
-
6
- export default component$(() => {
7
- useStyles$(styles);
8
-
9
- return (
10
- <Host class="docs">
11
- <Menu />
12
- <section class="docs-content">
13
- <Slot />
14
- </section>
15
- </Host>
16
- );
17
- });
18
-
19
- export const head: DocumentHead = ({ head }) => {
20
- return {
21
- title: `Docs: ${head.title}`,
22
- };
23
- };
@@ -1,32 +0,0 @@
1
- ---
2
- title: Welcome
3
- ---
4
-
5
- import { Counter } from '~/components/counter/counter';
6
-
7
- # Welcome
8
-
9
- Welcome to the fabulous Qwik City. QwikCity is our official kit to build amazing sites:
10
-
11
- - 🐎 Powered by Qwik. Zero hydration and instant interactivity.
12
- - 🗃 File based routing (like Nextjs)
13
- - 🌏 Deploy easily to the edge: Netlify, Cloudflare, Vercel, Deno...
14
- - 📖 Author content directly in Markdown or MDX. MDX brings the best of markdown and JSX, allowing you to render Qwik components directly in markdown, like this one:
15
-
16
- <Counter />
17
-
18
- ## Next steps
19
-
20
- Open your editor and check out the following:
21
-
22
- **The `src/routes` folder**
23
-
24
- This is where the main content lives. Adding folders and / or files (`.md`, `.mdx`, or `.tsx`) will automatically create new URLs. For example, code saved at `routes/dashboard/settings/index.tsx` will be accessible via the URL path `/dashboard/settings`.
25
-
26
- **The `src/routes/_layout` files and folders**
27
-
28
- These bring form to your content. Since different pages may need to be rendered by different layouts, QwikCity provides the ability to scope layouts to specific routes, while still allowing for easy reuse across different content. For any page without its own layout defined, the `src/routes/_layout.tsx` is used by default.
29
-
30
- **The `src/components` folder**
31
-
32
- QwikCity is still a normal Qwik app. Any custom component, design systems, or functionality should live here. Notice the `header`, `footer` and `content-nav` components. They are used by the `default` layout!