Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@
<img alt="Qwik Logo" width="400" src="https://cdn.builder.io/api/v1/image/assets%2FYJIGb4i01jvw0SRdL5Bt%2F667ab6c2283d4c4d878fb9083aacc10f" />
</p>

<a href="https://youtu.be/0dC11DMR3fU?t=154">
<img width="1229" alt="WWC22 - Qwik + Partytown: How to remove 99% of JavaScript from main thread" src="https://user-images.githubusercontent.com/111951/175145272-0df06434-7488-4e0e-933b-61358d4bd42b.png">
</a>

# The HTML-first framework

Qwik is designed for the fastest possible page load time, by delivering pure HTML with near 0 JavaScript for your pages to become interactive, regardless of how complex your site or app is. It achieves this via [resumability](https://github.com/BuilderIO/qwik/blob/main/packages/docs/src/pages/docs/concepts/resumable.mdx) of HTML and [ultra fine-grained lazy-loading](https://github.com/BuilderIO/qwik/blob/main/packages/docs/src/pages/docs/concepts/progressive.mdx) of code.
Expand Down
2 changes: 1 addition & 1 deletion cspell.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,5 @@
"Pinterest",
"Serializability"
],
"enableFiletypes": ["!mdx"]
"enableFiletypes": ["mdx"]
}
10 changes: 9 additions & 1 deletion packages/docs/src/pages/docs/INDEX
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@
- [Overview](overview.mdx)
- [Getting Started](getting-started.mdx)
- [Think Qwik](think-qwik.mdx)
- [Cheat Sheet](cheat-sheet.mdx)


## Component API

- [Overview](components/overview.mdx)
- [Anatomy](components/anatomy.mdx)
- [Hooks](components/hooks.mdx)
- [Events](components/events.mdx)
- [Lite elements](components/lite-components.mdx)
- [Context](components/context.mdx)
- [Lite components](components/lite-components.mdx)
- [Content projection](components/projection.mdx)
- [Rendering](components/rendering.mdx)

## Cheat Sheet

- [Components](cheat/components.mdx)
- [Serialization](cheat/serialization.mdx)

## Concepts

- [Resumable](concepts/resumable.mdx)
Expand Down
2 changes: 1 addition & 1 deletion packages/docs/src/pages/docs/advanced/containers.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ A typical site is composed of two logical parts:
1. The navigation that tends to stay constant across many pages, and
2. The outlet, which is the part of the page that changes based on which route the user navigated to.

We can model the two parts as two navigation and outlet containers. When the user first navigates to a route, the server responds with HTML, which contains containers for both the navigation and the outlet. Once the user navigates to the second route, there are three ways to solve the navigation:
We can model the two parts as two navigation and outlet containers. When the user first navigates to a route, the server responds with HTML, that contains containers for both the navigation and the outlet. Once the user navigates to the second route, there are three ways to solve the navigation:

1. The simplistic approach is to make a full round trip and download an entirely new page. The main downside is that the application loses all of its states on the client.
1. The classical approach is to treat any further navigation in JavaScript. We replace the current outlet component with the new outlet component and let the new component render. The disadvantage is that we need to download and execute the JavaScript.
Expand Down
17 changes: 6 additions & 11 deletions packages/docs/src/pages/docs/advanced/optimizer.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -31,22 +31,15 @@ const Counter = component(qrl('./chunk-a.js', 'Counter_onMount'));
```tsx
export const Counter_onMount = () => {
const store = useStore({ count: 0 });
return qrl('./chunk-b.js', 'Counter_onRender', [store]);
};
```

`chunk-b.js`:

```tsx
const Counter_onRender = () => {
const [store] = useLexicalScope();
return (
<button onClickQrl={qrl('./chunk-c.js', 'Counter_onClick', [store])}>{store.count}</button>
<button onClickQrl={qrl('./chunk-b.js', 'Counter_onClick', [store])}>
{store.count}
</button>
);
};
```

`chunk-c.js`:
`chunk-b.js`:

```tsx
const Counter_onClick = () => {
Expand All @@ -55,6 +48,8 @@ const Counter_onClick = () => {
};
```

Notice that every occurence of `$` results in a new lazy loadable symbol.


# `$` and Optimizer Rules

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ export function Component() {
Hello world
</div>
)
})
}
```

## Button with a click handler
Expand All @@ -47,9 +47,9 @@ export function Component() {
return (
<button onClick={() => console.log('click')}>
Click me
</div>
</button>
)
})
}
```

## Declare local state
Expand All @@ -75,13 +75,11 @@ export const Component = component$(() => {
export function Component() {
const [value, setValue] = useState(0);
return (
<Host>
<div>
Value is: ${value}
</div>
</Host>
<div>
Value is: ${value}
</div>
)
})
}
```

## Create a counter component
Expand All @@ -95,7 +93,7 @@ export const Counter = component$(() => {
});
return (
<Host>
<div>Value is: ${state.value}</div>
<div>Value is: ${state.count}</div>
<button onClick$={() => state.count++}>Increment</button>
</Host>
);
Expand All @@ -117,7 +115,7 @@ export function Counter() {
</button>
</>
)
})
}
```

## Create a clock that increments every second
Expand Down Expand Up @@ -157,10 +155,10 @@ export function Clock() {
});
return (
<div>
Seconds: ${state.seconds}
Seconds: ${seconds}
</div>
)
})
}
```

## Perform a fetch request every time the state changes
Expand Down Expand Up @@ -202,10 +200,10 @@ export function Fetch() {
.then((json) => setResponseJson(json));
}, [url]);
return (
<Host>
<>
<div>${responseJson.name}</div>
<input name="url" onInput={(ev) => setUrl(ev.target.value)} />
</Host>
</>
);
}
```
Expand Down Expand Up @@ -301,7 +299,7 @@ export function DynamicBackground() {
const [green, setGreen] = useState(0);
const [blue, setBlue] = useState(0);
return (
<Host style={
<div style={
'background': `rgb(${red}, ${green}, ${blue})`
}>
<button onClick={() => {
Expand All @@ -311,9 +309,9 @@ export function DynamicBackground() {
}}>
Change background
</button>
</Host>
</div>
)
})
}
```

## Create a component that renders a list of the presidents
Expand Down
98 changes: 98 additions & 0 deletions packages/docs/src/pages/docs/cheat/components.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
title: Components
---

# Common Component Patterns Cheat Sheet

## Declartion

```tsx
import {component$, useStore} from "@builder.io/qwik";

export const Greeter = component$(() => {
return <span>Hello World!</span>;
});
```

## Props

```tsx
import {component$, useStore} from "@builder.io/qwik";

interface GreeterProps {
salutation?: string;
name?: string;
}
export const Greeter = component$((props: GreeterProps) => {
const salutation = props.salutation || 'Hello';
const name = props.name || 'World';
return <span>{salutation} {name}!</span>;
});
```

### Event Props

Component props must be serializable, and therefore can not directly reffer to functions.

```tsx
import {component$, useStore, Qrl} from "@builder.io/qwik";

export const Parent = component$(() => {
return (
<MyButton doSomething$={() => console.log('Hello')}>
click
</MyButton>
);
});

interface MyButtonProps {
doSomethingQrl: QRL<() => void>
}
export const MyButton = component$((props: MyButtonProps) => {
return <button onClickQrl={props.doSomethingQrl}>click</button>;
});
```

## Events

## Watching for Changes

## Server
### Fetching Data

```tsx
import {component$, useStore, useServerMount$} from "@builder.io/qwik";

export const Greeter = component$(() => {
const store = useStore<{list: null|string[]}>({list: null});
useServerMount$(async () => {
store.list = await doSomethingToFetchDataOnServer();
});

return (
<ul>
{store.list && store.list.map((item) => <li>{item}</li>)}
</ul>
);
});
```

## Client
### Eagerly Executing Code

```tsx
import {component$, useStore, useClientEffet} from "@builder.io/qwik";

export const Greeter = component$(() => {
const store = useStore<{list: null|string[]}>({list: null});
useClientEffet$(async () => {
store.list = await doSomethingToFetchDataOnServer();
});

return (
<ul>
{store.list && store.list.map((item) => <li>{item}</li>)}
</ul>
);
});
```
53 changes: 53 additions & 0 deletions packages/docs/src/pages/docs/cheat/serialization.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
---
title: Serialization & Serialization Boundaries
---

# `$` Boundaries

## Rules

- Only serializable data can cross a `$` boundery.

## Serialization Boundery

A serialization boundery occures whenever you cross a lexical scope of a function that is converted into lazy loadable form. It is always denoted by `$(...)` (or `____$(...)`) See example:

```tsx
import {component$} from "@builder.io/qwik";

export const topLevel = Promise.resolve('nonserializable data');

export const Greeter = component$(() => {
// BEGIN component serialization boundery

// Referring to top level symbols that are exported is always allowed.
console.log(topLevel); // OK

const captureSerializable = 'serializable data';
const captureNonSerializable = Promise.resolve('nonserializable data');
return (
<button onClick$={() => {
// BEGIN onClick serialization boundery

// Referring to top level symbols that are exported is always allowed.
// Even if the value is non-serializable.
console.log(topLevel); // OK

// Capturing a non-toplevel variable is allowed only if:
// - declaed as `const`
// - is serializable (runtime error)
console.log(captureSerializable); // OK

// Reffering to captureNonSerializable will pass static analysis but
// will fail at runtime because Qwik does not know how to serilize it.
console.log(captureNonSerializable); // RUNTIME ERROR

// END onClick serialization boundery
}}>
click
</button>
);
// BEGIN component serialization boundery
});

```
4 changes: 2 additions & 2 deletions packages/docs/src/pages/docs/components/anatomy.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -265,8 +265,8 @@ const Parent = component$(() => {
In the above example the Optimizer transforms the above to:

```tsx
const Child = component$(qrl('./chunk-a', 'Child_onMount'));
const Parent = component$(qrl('./chunk-b', 'Parent_onMount'));
const Child = componentQrl(qrl('./chunk-a', 'Child_onMount'));
const Parent = componentQrl(qrl('./chunk-b', 'Parent_onMount'));
const Parent_onMount = () => qrl('./chunk-c', 'Parent_onRender');
const Parent_onRender = () => (
<section>
Expand Down
Loading