create-qwik 0.0.31 → 0.0.34-dev20220701233003

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 (93) hide show
  1. package/create-qwik +45 -45
  2. package/index.js +9 -9
  3. package/package.json +2 -2
  4. package/starters/apps/base/gitignore +4 -0
  5. package/starters/apps/base/package.json +8 -8
  6. package/starters/apps/base/src/entry.dev.tsx +1 -1
  7. package/starters/apps/{library → base}/src/entry.ssr.tsx +1 -1
  8. package/starters/apps/base/src/root.tsx +1 -1
  9. package/starters/apps/blank/package.json +18 -0
  10. package/starters/apps/{starter → blank}/src/components/app/app.tsx +0 -0
  11. package/starters/apps/{starter → blank}/src/components/logo/logo.tsx +0 -0
  12. package/starters/apps/blank/src/entry.express.tsx +52 -0
  13. package/starters/apps/{todo → blank}/src/entry.ssr.tsx +1 -1
  14. package/starters/apps/{starter-partytown → blank}/src/global.css +0 -0
  15. package/starters/apps/{starter → blank}/src/root.tsx +1 -1
  16. package/starters/apps/library/package.json +0 -1
  17. package/starters/apps/library/src/root.tsx +1 -1
  18. package/starters/apps/qwik-city/package.json +4 -2
  19. package/starters/apps/qwik-city/src/components/footer/footer.css +21 -4
  20. package/starters/apps/qwik-city/src/components/footer/footer.tsx +23 -9
  21. package/starters/apps/qwik-city/src/components/head/analytics.tsx +13 -0
  22. package/starters/apps/qwik-city/src/components/head/head.tsx +37 -0
  23. package/starters/apps/qwik-city/src/components/head/social.tsx +10 -0
  24. package/starters/apps/qwik-city/src/components/header/header.css +34 -2
  25. package/starters/apps/qwik-city/src/components/header/header.tsx +41 -13
  26. package/starters/apps/qwik-city/src/components/menu/menu.css +3 -0
  27. package/starters/apps/qwik-city/src/components/menu/menu.tsx +39 -0
  28. package/starters/apps/qwik-city/src/root.tsx +8 -22
  29. package/starters/apps/qwik-city/src/routes/__auth/_layout.tsx +17 -0
  30. package/starters/apps/qwik-city/src/routes/__auth/sign-in.tsx +29 -0
  31. package/starters/apps/qwik-city/src/routes/__auth/sign-up.tsx +33 -0
  32. package/starters/apps/qwik-city/src/routes/_layout.tsx +15 -0
  33. package/starters/apps/qwik-city/src/routes/about-us.tsx +21 -0
  34. package/starters/apps/qwik-city/src/routes/api/[org]/[user].json/index.ts +42 -0
  35. package/starters/apps/qwik-city/src/routes/api/_layout-foo/api.css +14 -0
  36. package/starters/apps/qwik-city/src/routes/api/_layout-foo/index.tsx +40 -0
  37. package/starters/apps/qwik-city/src/routes/api/data.json.ts +21 -0
  38. package/starters/apps/qwik-city/src/routes/api/index@foo.tsx +36 -0
  39. package/starters/apps/qwik-city/src/routes/blog/[...slug].tsx +13 -0
  40. package/starters/apps/qwik-city/src/routes/blog/_layout/index.tsx +21 -0
  41. package/starters/apps/qwik-city/src/routes/blog/index.md +7 -0
  42. package/starters/apps/qwik-city/src/routes/dashboard/_layout-dashboard.tsx +18 -0
  43. package/starters/apps/qwik-city/src/routes/dashboard/index.tsx +9 -0
  44. package/starters/apps/qwik-city/src/routes/dashboard/profile@dashboard.tsx +10 -0
  45. package/starters/apps/qwik-city/src/routes/dashboard/settings/index@dashboard.tsx +10 -0
  46. package/starters/apps/qwik-city/src/routes/docs/[category]/[id]/index.tsx +15 -0
  47. package/starters/apps/qwik-city/src/routes/docs/_layout/docs.css +9 -0
  48. package/starters/apps/qwik-city/src/routes/docs/_layout/index.tsx +25 -0
  49. package/starters/apps/qwik-city/src/routes/docs/_menu.md +9 -0
  50. package/starters/apps/qwik-city/src/{pages/index.mdx → routes/docs/getting-started.mdx} +1 -1
  51. package/starters/apps/qwik-city/src/routes/docs/index.tsx +18 -0
  52. package/starters/apps/qwik-city/src/routes/docs/introduction/index.md +7 -0
  53. package/starters/apps/qwik-city/src/routes/index.tsx +11 -0
  54. package/starters/apps/qwik-city/tsconfig.json +24 -0
  55. package/starters/apps/qwik-city/vite.config.ts +3 -7
  56. package/starters/features/prettier/package.json +1 -1
  57. package/starters/features/react/package.json +26 -0
  58. package/starters/{apps/qwik-city → features/react}/src/entry.ssr.tsx +3 -2
  59. package/starters/features/react/src/react/app.tsx +14 -0
  60. package/starters/servers/cloudflare-pages/functions/[[path]].ts +1 -1
  61. package/starters/servers/cloudflare-pages/src/entry.cloudflare.tsx +2 -2
  62. package/starters/servers/express/src/entry.express.tsx +5 -38
  63. package/starters/servers/netlify/package.json +1 -1
  64. package/starters/apps/qwik-city/src/components/app/app.tsx +0 -13
  65. package/starters/apps/qwik-city/src/components/page/page.tsx +0 -24
  66. package/starters/apps/qwik-city/src/components/sidebar/sidebar.css +0 -12
  67. package/starters/apps/qwik-city/src/components/sidebar/sidebar.tsx +0 -54
  68. package/starters/apps/qwik-city/src/entry.dev.tsx +0 -13
  69. package/starters/apps/qwik-city/src/layouts/default/default.css +0 -171
  70. package/starters/apps/qwik-city/src/layouts/default/default.tsx +0 -24
  71. package/starters/apps/qwik-city/src/layouts/not-found/not-found.css +0 -0
  72. package/starters/apps/qwik-city/src/layouts/not-found/not-found.tsx +0 -18
  73. package/starters/apps/qwik-city/src/pages/INDEX +0 -16
  74. package/starters/apps/qwik-city/src/pages/blog/progressive.mdx +0 -70
  75. package/starters/apps/qwik-city/src/pages/blog/reactivity.mdx +0 -155
  76. package/starters/apps/qwik-city/src/pages/blog/resumable.mdx +0 -107
  77. package/starters/apps/starter/package.json +0 -10
  78. package/starters/apps/starter/src/entry.ssr.tsx +0 -15
  79. package/starters/apps/starter/src/global.css +0 -3
  80. package/starters/apps/starter-partytown/package.json +0 -13
  81. package/starters/apps/starter-partytown/src/components/app/app.tsx +0 -89
  82. package/starters/apps/starter-partytown/src/entry.ssr.tsx +0 -16
  83. package/starters/apps/starter-partytown/src/root.tsx +0 -36
  84. package/starters/apps/todo/package.json +0 -7
  85. package/starters/apps/todo/src/components/app/app.tsx +0 -39
  86. package/starters/apps/todo/src/components/app/base.css +0 -141
  87. package/starters/apps/todo/src/components/app/index.css +0 -378
  88. package/starters/apps/todo/src/components/body/body.tsx +0 -16
  89. package/starters/apps/todo/src/components/footer/footer.tsx +0 -63
  90. package/starters/apps/todo/src/components/header/header.tsx +0 -40
  91. package/starters/apps/todo/src/components/item/item.tsx +0 -76
  92. package/starters/apps/todo/src/root.tsx +0 -15
  93. package/starters/apps/todo/src/state/state.ts +0 -29
@@ -1,24 +0,0 @@
1
- import { component$ } from '@builder.io/qwik';
2
- import { useHeadMeta, usePage } from '@builder.io/qwik-city';
3
- import NotFound from '../../layouts/not-found/not-found';
4
-
5
- export const Page = component$(() => {
6
- const page = usePage();
7
- if (page) {
8
- const attrs = page.attributes;
9
- const Layout = page.layout;
10
- const Content = page.content;
11
-
12
- useHeadMeta({
13
- title: attrs.title + ' - Qwik',
14
- description: attrs.description,
15
- });
16
-
17
- return (
18
- <Layout>
19
- <Content />
20
- </Layout>
21
- );
22
- }
23
- return <NotFound />;
24
- });
@@ -1,12 +0,0 @@
1
- aside {
2
- padding: 10px;
3
- }
4
-
5
- .menu h5 {
6
- font-size: 18px;
7
- font-weight: 800;
8
- }
9
-
10
- .menu li a {
11
- text-decoration: underline;
12
- }
@@ -1,54 +0,0 @@
1
- import { component$, Host, useScopedStyles$ } from '@builder.io/qwik';
2
- import { usePage, usePageIndex } from '@builder.io/qwik-city';
3
- import styles from './sidebar.css?inline';
4
-
5
- export const SideBar = component$(
6
- () => {
7
- useScopedStyles$(styles);
8
- const page = usePage();
9
- const navIndex = usePageIndex();
10
- if (!page) {
11
- return null;
12
- }
13
-
14
- return (
15
- <Host class="sidebar">
16
- <nav class="breadcrumbs">
17
- <ol itemScope itemType="https://schema.org/BreadcrumbList">
18
- {page.breadcrumbs.map((b) => (
19
- <li>
20
- {b.text}
21
- <meta itemProp="position" content="0"></meta>
22
- </li>
23
- ))}
24
- </ol>
25
- </nav>
26
- <nav class="menu">
27
- {navIndex
28
- ? navIndex.items?.map((item) => (
29
- <>
30
- <h5>{item.text}</h5>
31
- <ul>
32
- {item.items?.map((item) => (
33
- <li>
34
- <a
35
- href={item.href}
36
- class={{
37
- 'is-active':
38
- new URL(page.url, 'https://qwik.builder.io/').pathname === item.href,
39
- }}
40
- >
41
- {item.text}
42
- </a>
43
- </li>
44
- ))}
45
- </ul>
46
- </>
47
- ))
48
- : null}
49
- </nav>
50
- </Host>
51
- );
52
- },
53
- { tagName: 'aside' }
54
- );
@@ -1,13 +0,0 @@
1
- import { render } from '@builder.io/qwik';
2
- import { Root } from './root';
3
-
4
- /**
5
- * Development entry point using only client-side modules:
6
- * - Do not use this mode in production!
7
- * - No SSR
8
- * - No portion of the application is pre-rendered on the server.
9
- * - All of the application is running eagerly in the browser.
10
- * - More code is transferred to the browser than in SSR mode.
11
- * - Optimizer/Serialization/Deserialization code is not exercised!
12
- */
13
- render(document, <Root />);
@@ -1,171 +0,0 @@
1
- .docs {
2
- --tw-bg-opacity: 1;
3
- background-color: rgb(255 255 255 / var(--tw-bg-opacity));
4
- --tw-text-opacity: 1;
5
- color: rgb(17 24 39 / var(--tw-text-opacity));
6
- display: grid;
7
- grid-template-columns: 1fr 3fr;
8
- grid-template-areas:
9
- 'header header'
10
- 'sidemenu content';
11
- }
12
-
13
- .docs header {
14
- grid-area: header;
15
- }
16
-
17
- .docs aside {
18
- grid-area: sidemenu;
19
- }
20
-
21
- .docs main {
22
- margin-left: auto;
23
- margin-right: auto;
24
- margin-top: 3.5rem;
25
- min-height: 100vh;
26
- grid-area: content;
27
- }
28
-
29
- .docs article {
30
- padding-left: 1.5rem;
31
- padding-right: 1.5rem;
32
- }
33
-
34
- .docs article a {
35
- color: var(--qwik-dark-blue);
36
- text-decoration: underline;
37
- }
38
-
39
- .docs article a:hover {
40
- text-decoration: none;
41
- }
42
-
43
- .docs article h1 {
44
- --tw-text-opacity: 1;
45
- color: rgb(15 23 42 / var(--tw-text-opacity));
46
- font-size: 3rem;
47
- line-height: 1;
48
- font-weight: 700;
49
- margin-bottom: 1.5rem;
50
- position: relative;
51
- }
52
-
53
- .docs article h2,
54
- .docs article h3,
55
- .docs article h4,
56
- .docs article h5,
57
- .docs article h6 {
58
- font-size: 1.25rem;
59
- line-height: 1.75rem;
60
- font-weight: 600;
61
- --tw-text-opacity: 1;
62
- color: rgb(15 23 42 / var(--tw-text-opacity));
63
- margin-top: 2rem;
64
- margin-bottom: 1rem;
65
- position: relative;
66
- scroll-margin-top: 80px;
67
- }
68
-
69
- .docs article h2 {
70
- font-size: 1.875rem;
71
- line-height: 2.25rem;
72
- }
73
-
74
- .docs h2 a,
75
- .docs h3 a,
76
- .docs h4 a,
77
- .docs h5 a,
78
- .docs h6 a {
79
- position: absolute;
80
- width: 100%;
81
- height: 32px;
82
- }
83
-
84
- .icon-link {
85
- display: none;
86
- }
87
-
88
- .icon-link::after {
89
- position: absolute;
90
- content: '#';
91
- left: -23px;
92
- }
93
-
94
- h2 a:hover .icon,
95
- h3 a:hover .icon,
96
- h4 a:hover .icon,
97
- h5 a:hover .icon,
98
- h6 a:hover .icon {
99
- display: inline;
100
- }
101
-
102
- .docs article p {
103
- margin-top: 1.25rem;
104
- margin-bottom: 1.25rem;
105
- font-size: 17px;
106
- }
107
-
108
- .docs article ul,
109
- .docs article ol {
110
- margin-top: 1rem;
111
- margin-bottom: 1rem;
112
- margin-left: 2rem;
113
- font-size: 17px;
114
- line-height: 1.7;
115
- list-style: disc;
116
- }
117
-
118
- .docs article li {
119
- margin-top: 0.25rem;
120
- margin-bottom: 0.25rem;
121
- padding-left: 0.5rem;
122
- }
123
-
124
- .docs article pre {
125
- overflow: auto;
126
- color: white;
127
- background-color: rgb(1 31 51);
128
- padding: 18px 15px;
129
- border-radius: 8px;
130
- }
131
-
132
- .docs article pre code {
133
- display: block;
134
- max-width: 50px;
135
- background-color: transparent;
136
- }
137
-
138
- .docs article code {
139
- background-color: rgb(224, 224, 224);
140
- padding: 2px 4px;
141
- border-radius: 3px;
142
- font-size: 0.9em;
143
- line-height: 1.4;
144
- }
145
-
146
- @media (max-width: 640px) {
147
- .docs article code {
148
- word-break: break-all;
149
- }
150
- }
151
-
152
- .docs article th,
153
- .docs article td {
154
- padding: 6px;
155
- vertical-align: top;
156
- }
157
-
158
- .docs article th:first-child,
159
- .docs article td:first-child {
160
- padding-left: 0;
161
- }
162
-
163
- .docs article th:last-child,
164
- .docs article td:last-child {
165
- padding-right: 0;
166
- }
167
-
168
- .docs article img {
169
- border-radius: 5px;
170
- overflow: hidden;
171
- }
@@ -1,24 +0,0 @@
1
- import { component$, Host, Slot, useScopedStyles$ } from '@builder.io/qwik';
2
- import { Footer } from '../../components/footer/footer';
3
- import { Header } from '../../components/header/header';
4
- import { SideBar } from '../../components/sidebar/sidebar';
5
- import styles from './default.css?inline';
6
-
7
- const DefaultLayout = component$(() => {
8
- useScopedStyles$(styles);
9
-
10
- return (
11
- <Host class="docs">
12
- <Header />
13
- <SideBar />
14
- <main>
15
- <article>
16
- <Slot />
17
- <Footer />
18
- </article>
19
- </main>
20
- </Host>
21
- );
22
- });
23
-
24
- export default DefaultLayout;
@@ -1,18 +0,0 @@
1
- import { component$, Host, useScopedStyles$ } from '@builder.io/qwik';
2
- import { Header } from '../../components/header/header';
3
- import { SideBar } from '../../components/sidebar/sidebar';
4
- import styles from './not-found.css?inline';
5
-
6
- const NotFound = component$(() => {
7
- useScopedStyles$(styles);
8
-
9
- return (
10
- <Host class="docs">
11
- <Header />
12
- <SideBar />
13
- <main>Not Found</main>
14
- </Host>
15
- );
16
- });
17
-
18
- export default NotFound;
@@ -1,16 +0,0 @@
1
- # Site struct
2
-
3
- ## Welcome
4
-
5
- - [Welcome](index.mdx)
6
-
7
- ## Blog
8
-
9
- - [Resumable](blog/resumable.mdx)
10
- - [Progressive](blog/progressive.mdx)
11
- - [Reactive](blog/reactivity.mdx)
12
-
13
- ## Docs
14
-
15
- - [Qwik](https://qwik.builder.io)
16
- - [Partytown](https://partytown.builder.io/)
@@ -1,70 +0,0 @@
1
- ---
2
- title: Progressively
3
- ---
4
-
5
- # Progressively
6
-
7
- Progressively is about downloading code as the application needs, without having to download the entire codebase eagerly.
8
-
9
- This connect with qwik's core tenant which focus on delaying **the loading** and execution of JavaScript for as long as possible. Qwik needs to break up the application into many lazy loadable chunks to achieve that.
10
-
11
- ## Current state-of-the-art
12
-
13
- [Existing frameworks suffer of two problems](https://www.builder.io/blog/dont-blame-the-developer-for-what-the-frameworks-did):
14
-
15
- - Lazy loading boundaries are 100% delegated to the developer
16
- - Frameworks can only lazy load components that are not in the current render tree.
17
-
18
- The issue is that the frameworks need to reconcile their internal state with the DOM. And that means that at least once on application hydration, they need to be able to do a full render to rebuild the framework's internal state. After the first render, the frameworks can be more surgical about their updates, but the damage has been done, the code has been downloaded. So we have two issues:
19
-
20
- Frameworks need to download and execute components to rebuild the render tree on startup. (See hydration is pure overhead) This forces eager download and execution of all components in the render tree.
21
- The event handlers come with the components even though they are not needed at the time of rendering. The inclusion of event handlers forces the download of unnecessary code.
22
-
23
- ## Solution
24
-
25
- Qwik architecture takes full advantage of modern tooling to automate the problem of entry point generation. Developers can write components normally, while the Qwik optimizer will split the components into chunks and download them as needed.
26
-
27
- In addition the framework runtime does not need to download code that is not required for interactivity, even if the component is part of the render tree.
28
-
29
- ### Optimizer
30
-
31
- Optimizer is a code transformation that extracts functions into top-level importable symbols, which allows the Qwik runtime to lazy-load the JavaScript on a needed basis.
32
-
33
- The Optimizer and Qwik runtime work together to achieve the desired result of fine-grained lazy loading.
34
-
35
- Without Optimizer either:
36
-
37
- - The code would have to be broken up by the developer into importable parts. This would be unnatural to write an application, making for a bad DX.
38
- - The application would have to load a lot of unnecessary code as there would be no lazy-loaded boundaries.
39
-
40
- Qwik runtime must understand the Optimizer output. The biggest difference to comprehend is that by breaking up the component into lazy-loadable chunks, the lazy-loading requirement introduces asynchronous code into the framework. The framework has to be written differently to take asynchronicity into account. Existing frameworks assume that all code is available synchronously. This assumption prevents an easy insertion of lazy-loading into existing frameworks. (For example, when a new component is created, the framework assumes that its initialization code can be invoked in a synchronous fashion. If this is the first time component is referenced, then its code needs to be lazy-loaded, and therefore the framework must take that into account.)
41
-
42
- ### Lazy-loading
43
-
44
- Lazy-loading is asynchronous. Qwik is an asynchronous framework. Qwik understands that at any time, it may not have a reference to a callback, and therefore, it may need to lazy-load it. (In contrast, most existing frameworks assume that all of the code is available synchronously, making lazy-loading non-trivial.)
45
-
46
- In Qwik everything is lazy-loadable:
47
-
48
- - Component on-render (initialization block and render block)
49
- - Component on-watch (side-effects, only downloaded if inputs change)
50
- - Listeners (only downloaded on interaction)
51
- - Styles (Only downloaded if the server did not already provide them)
52
-
53
- Lazy-loading is a core property of the framework and not an afterthought.
54
-
55
- ### Optimizer and `$`
56
-
57
- Let's look at our example again:
58
-
59
- ```tsx
60
- const Counter = component$(() => {
61
- const store = useStore({ count: 0 });
62
-
63
- return <button onClick$={() => store.count++}>{store.count}</button>;
64
- });
65
- ```
66
-
67
- Notice the presence of `$` in the code. `$` is a marker that tells the Optimizer that the function
68
- following it should be lazy-loaded.
69
- The `$` is a single character that hints to the Optimizer and the developer to let them know
70
- that asynchronous lazy-loading occurs here.
@@ -1,155 +0,0 @@
1
- ---
2
- title: Overview
3
- ---
4
-
5
- # Reactivity
6
-
7
- Reactivity is a key component of Qwik. Reactivity allows Qwik to track which components are subscribed to which state. This information enables Qwik to invalidate only the relevant component on state change, which minimizes the number of components that need to be rerendered. Without reactivity, a state change would require rerendering from the root component, which would force the whole component tree to be eagerly downloaded.
8
-
9
- # Proxy
10
-
11
- Reactivity requires that the framework keeps track of the relationship between the state of the applications and the components. The framework must render the whole application at least once to build the reactivity graph. The build of reactive graph initially happens on the server and is serialized to HTML so that the browser can use the information without being forced to do a single pass through all components to rebuild the graph. (Qwik does not need to do hydration to register events or build up the reactivity graph.)
12
-
13
- Reactivity can be done in a few ways:
14
-
15
- 1. using explicit registration of listeners using `.subscribe()` (for example, RxJS)
16
- 2. using implicit registration using a compiler (for example, Svelte)
17
- 3. using implicit registration using proxies.
18
-
19
- Qwik uses proxies for a few reasons:
20
-
21
- 1. using explicit registration such as `.subscribe()` would require that the system would need to serialize all of the subscribe listeners to avoid hydration. Serializing subscribe closures would not be possible as all the subscribe functions would have to be lazy-loaded and asynchronous (too expensive).
22
- 2. using the compiler to create graphs implicitly would work, but only for components. Intra component communications would still require `.subscribe()` methods and hence suffer the issues described above.
23
-
24
- Because of the above constraints, Qwik uses proxies to keep track of the reactivity graph.
25
-
26
- - use `useStore()` to create a store proxy.
27
- - the proxy notices the reads and creates subscriptions that are serializable.
28
- - the proxy notices the writes and uses the subscription information to invalidate the relevant components.
29
-
30
- ## Counter Example
31
-
32
- ```tsx
33
- const Counter = component$(() => {
34
- const store = useStore({ count: 0 });
35
-
36
- return <button onClick$={store.count++}>{store.count}</button>;
37
- });
38
- ```
39
-
40
- 1. The server performs an initial render of the component. The server rendering includes creating the proxy represented by `store`.
41
- 2. The initial render invokes the OnRender method, which has a reference to the `store` proxy. The rendering puts the proxy to "learn" mode. During the build-up of JSX, the proxy observers a read to `count` property. Because the proxy is in the "learn" mode, it records that the `Counter` has a subscription on the `store.count`.
42
- 3. The server serializes the state of the application into HTML. This includes the `store` as well as subscription information which says that `Counter` is subscribed to `store.count`.
43
- 4. In the browser, the user clicks the button. Because the click event handler closed over `store`, the Qwik restores the store proxy. The proxy contains the application state (the count) and the subscription, which associates the `Counter` with `state.count`.
44
- 5. The event handler increments the `store.count`. Because the `store` is a proxy, it notices the write and uses the subscription information to invalidate the `Counter`.
45
- 6. After `requestAnimationFrame`, the `Counter` downloads the rendering function and reruns the OnRender.
46
- 7. During the OnRender, the subscription list is cleared, and a new subscription list is built up by observing what reads the JSX building performs.
47
-
48
- ## Unsubscribe example
49
-
50
- ```tsx
51
- const ComplexCounter = component$(() => {
52
- const store = useStore({ count: 0, visible: true });
53
-
54
- return (
55
- <>
56
- <button onClick$={(store.visible = !store.visible)}>{store.visible ? 'hide' : 'show'}</button>
57
- <button onClick$={store.count++}>increment</button>
58
- {store.visible ? <span>{store.count}</span> : null}
59
- </>
60
- );
61
- });
62
- ```
63
-
64
- This example is a more complicated counter.
65
-
66
- - It contains the `increment` button, which always increments `store.count`.
67
- - It contains a `show`/`hide` button which determines if the count is shown.
68
-
69
- 1. On the initial render, the count is visible. Therefore the server creates a subscription that records that `ComplexCounter` needs to get rerender if either `store.count` or `store.visible` changes.
70
- 2. If the user clicks on `hide`, the `ComplexCounter` rerenders. The rerendering clears all of the subscriptions and records new ones. This time the JSX does not read `store.count`. Therefore, only `store.visible` gets added to the list of subscriptions.
71
- 3. User clicking on `increment` will update `store.count`, but doing so will not cause the component to rerender. This is correct because the counter is not visible, so rerendering would be a no-op.
72
- 4. If the user clicks `show` the component will rerender and this time the JSX will read both `store.visible` as well as `store.count`. The subscription list is once again updated.
73
- 5. Now, clicking on `increment` updates the `store.count`. Because the count is visible, the `ComplexCounter` is subscribed to `store.count`.
74
-
75
- Notice how the set of subscriptions automatically updates as the component renders different branches of its JSX. The advantage of the proxy is that the subscriptions update automatically as the applications execute, and the system can always compute the smallest set of invalidated components.
76
-
77
- ## Deep objects
78
-
79
- So far, the examples show the store (`useStore()`) was a simple object with primitive values. However, the same behavior works on all properties of the store recursively.
80
-
81
- ```tsx
82
- const MyComp = component$(() => {
83
- const store = useStore({
84
- person: { first: null, last: null },
85
- location: null
86
- });
87
-
88
- store.location = {street: 'main st'};
89
-
90
- return (
91
- <div>
92
- <div>{store.person.last}, {store.person.first}</div>
93
- </div>{store.location.street}</div>
94
- </div>
95
- );
96
- })
97
- ```
98
-
99
- In the above examples, the Qwik will automatically wrap child objects `person` and `location` into a proxy and correctly create subscriptions on all deep properties.
100
-
101
- The wrapping behavior described above has one surprising side-effect. Writing and reading from a proxy auto wraps the object, which means that the identity of the object changes. This should normally not be an issue, but it is something that the developer should keep in mind.
102
-
103
- ```tsx
104
- const MyComp = component$(() => {
105
- const store = useStore({ person: null });
106
- const person = { first: 'John', last: 'Smith' };
107
- store.person = person; // `store.person auto wraps object into proxy`
108
-
109
- if (store.person !== person) {
110
- // The consequence of auto wrapping is that the object identity changes.
111
- console.log('store auto-wrapped person into a proxy');
112
- }
113
- });
114
- ```
115
-
116
- ## Out-of-order rendering
117
-
118
- Qwik components can render out of order. A component can render without forcing a parent component to render first or to force child components to render as a consequence of the component render. This is an important property of Qwik because it allows Qwik applications to only re-render components which have been invalidated due to state change rather than re-rendering the whole component tree on change.
119
-
120
- When components render, they need to have access to their props. Parent components create props. The props must be serializable for the component to render independently from the parent. (See serialization for an in-depth discussion on what is serializable.)
121
-
122
- ## Invalidating child components
123
-
124
- When re-rendering a component, the child component props can stay the same or be updated. A child component only invalidates if the child component props change.
125
-
126
- ```tsx
127
- const Child = component$((props: { count: number }) => {
128
- return <span>{props.count}</span>;
129
- });
130
-
131
- const MyApp = component$(() => {
132
- const store = useStore({ a: 0, b: 0, c: 0 });
133
-
134
- return (
135
- <>
136
- <button onClick$={() => store.a++}>a++</button>
137
- <button onClick$={() => store.b++}>b++</button>
138
- <button onClick$={() => store.c++}>c++</button>
139
- {JSON.stringify(store)}
140
-
141
- <Child count={store.a} />
142
- <Child count={store.b} />
143
- </>
144
- );
145
- });
146
- ```
147
-
148
- In the above example, there are two `<Child/>` components.
149
-
150
- - Every time a button is clicked, one of the three counters is incremented. A change of counter state will cause the `MyApp` component to re-render on each click.
151
- - If `store.c` has been incremented, none of the child components get re-render. (And therefore, their code does not get lazy-loaded.)
152
- - If `store.a` has been incremented than only `<Child count={store.a}/>` will re-render.
153
- - If `store.b` has been incremented than only `<Child count={store.b}/>` will re-render.
154
-
155
- Notice that the child components only re-render when their props change. This is an important property of Qwik applications as it significantly limits the amount of re-rendering the application must do on state change. While less re-rendering has performance benefits, the real benefit is that large portions of the applications do not get downloaded if they don't need to be re-rendered.