Skip to content

Commit

Permalink
fix: qDynamicPlatform (QwikDev#1139)
Browse files Browse the repository at this point in the history
  • Loading branch information
manucorporat authored Aug 24, 2022
1 parent 85925ae commit 1757694
Show file tree
Hide file tree
Showing 78 changed files with 317 additions and 327 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"private": true,
"name": "qwik-monorepo",
"version": "0.0.104",
"version": "0.0.105",
"scripts": {
"build": "tsm scripts/index.ts --tsc --build --qwikcity --api --platform-binding-wasm-copy",
"build.full": "tsm scripts/index.ts --tsc --build --api --eslint --qwikcity --qwikreact --platform-binding --wasm",
Expand Down
2 changes: 1 addition & 1 deletion packages/create-qwik/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-qwik",
"version": "0.0.104",
"version": "0.0.105",
"description": "Interactive CLI and API for generating Qwik projects.",
"bin": "create-qwik",
"main": "index.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ In certain cases, sometimes we need to make the build output directory different
## Wrong Way

Usually with Vite.js we do it like this:

```js
// vite.config.js
import { defineConfig } from 'vite';
Expand All @@ -26,7 +27,7 @@ export default defineConfig(() => {
return {
/* VITE_CONFIG */
build: {
outDir: '../resources/' // This will be overrided to `dist` by qwikVite() setting
outDir: '../resources/', // This will be overrided to `dist` by qwikVite() setting
},
plugins: [
qwikCity({
Expand All @@ -47,20 +48,21 @@ However, it will be overridden by the settings of QwikVite() so nothing happens
## The Right Way

So instead of changing the settings in Vite.js directly, we just need to change the settings in QwikVite() like this:

```ts
import { defineConfig } from "vite";
import { qwikVite } from "@builder.io/qwik/optimizer";
import { qwikCity } from "@builder.io/qwik-city/vite";
import tsconfigPaths from "vite-tsconfig-paths";
import { defineConfig } from 'vite';
import { qwikVite } from '@builder.io/qwik/optimizer';
import { qwikCity } from '@builder.io/qwik-city/vite';
import tsconfigPaths from 'vite-tsconfig-paths';

export default defineConfig(() => {
return {
ssr: { target: "webworker", noExternal: true },
ssr: { target: 'webworker', noExternal: true },
plugins: [
qwikCity(),
qwikVite({
client: {
outDir: "resources/", // This is the right setting
outDir: 'resources/', // This is the right setting
},
}),
tsconfigPaths(),
Expand Down
12 changes: 3 additions & 9 deletions packages/docs/src/routes/docs/advanced/optimizer/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ title: Optimizer Rules
fetch: https://hackmd.io/@mhevery/rkydmxJZ9
---


# Optimizer

Qwik's philosophy is to delay loading code for as long as possible. To do that, Qwik relies on Optimizer to re-arrange the code for lazy loading. The Optimizer is code level transformation that runs as part of the rollup. (Optimizer is written in Rust (and available as WASM) for instant performance)
Expand Down Expand Up @@ -31,11 +30,7 @@ const Counter = component(qrl('./chunk-a.js', 'Counter_onMount'));
```tsx
export const Counter_onMount = () => {
const store = useStore({ count: 0 });
return (
<button onClick$={qrl('./chunk-b.js', 'Counter_onClick', [store])}>
{store.count}
</button>
);
return <button onClick$={qrl('./chunk-b.js', 'Counter_onClick', [store])}>{store.count}</button>;
};
```

Expand All @@ -50,7 +45,6 @@ const Counter_onClick = () => {

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


# `$` and Optimizer Rules

Optimizer runs as part of the bundling step of building the application. The purpose of the Optimizer is to break up the application into many small lazy-loadable chunks. The Optimizer moves expressions (usually functions) into new files and leaves behind a reference pointing to where the expression was moved.
Expand Down Expand Up @@ -263,8 +257,8 @@ The Optimizer can lazy-load a function closure, which lexically captures variabl

Since not all valid JavaScript is valid Optimizer code, keep in mind the following rules:

* All captured variables must be declared as a `const`.
* All captured variables must be either:
- All captured variables must be declared as a `const`.
- All captured variables must be either:
- serializable
- importable (either `import` or `export` in this file)

Expand Down
11 changes: 6 additions & 5 deletions packages/docs/src/routes/docs/advanced/prefetching/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,25 @@ title: Prefetching

# Prefetching

**QUESTION**: *Is lazy loading on user events slow because the user must wait for the code to download?*
**QUESTION**: _Is lazy loading on user events slow because the user must wait for the code to download?_

Yes, that would create a noticeable delay, especially on slow 3G networks. This is why code pre-fetching is an important part of Qwik applications.

Prefetching code ensures that all of the necessary code for running the application is fetched immediately on navigating to the page. This way, when the user performs an action, the code for that action comes from the pre-fetch cache rather than the network. The result is that the code execution is instant.
Prefetching code ensures that all of the necessary code for running the application is fetched immediately on navigating to the page. This way, when the user performs an action, the code for that action comes from the pre-fetch cache rather than the network. The result is that the code execution is instant.

Open this page in DevTools and scroll to the button of `<body>` element. Notice presence of `<link href="..." rel="prefetch" as="script">` elements. These elements direct the browser to prefetch the code for the page.

**QUESTION**: *Doesn't code prefetch results in the same behavior as existing frameworks that download and execute all of the code eagerly?*
**QUESTION**: _Doesn't code prefetch results in the same behavior as existing frameworks that download and execute all of the code eagerly?_

No, for several reasons:

- Existing frameworks must download and execute all of the code (hydration) before the application can be interactive. Typically the download of the code is a smaller time cost than the execution of the code.
- Qwik code prefetch only downloads but does not execute the code. Therefore even if Qwik prefetches the same amount of code as the existing frameworks, the result is significant time cost savings.
- Qwik prefetches only the code which is needed for the current page. Qwik never downloads code associated with components that are static. In the worst case, Qwik prefetches the same amount of code as the existing frameworks' best case. In most cases, Qwik prefetches a small fraction of code compared to the existing frameworks.
- Prefetching of code can happen on other threads than the main thread. Many browsers can even pre-parse the AST of the code off the main thread.
- Prefetching of code can happen on other threads than the main thread. Many browsers can even pre-parse the AST of the code off the main thread.
- If the user interaction happens before the prefetch is completed, the browser will automatically prioritize the interaction chunk before the remaining prefetch chunks.
- Qwik can break up the application into many small chunks, and these chunks can be downloaded in the order of probability that the user will interact with them. Existing frameworks have trouble breaking up applications into small chunks, and there is no easy way to prioritize the chunk download order because hydration requires a single "main" entry point to the application.

**QUESTION**: *Who is responsible for knowing what code to prefetch?*
**QUESTION**: _Who is responsible for knowing what code to prefetch?_

Qwik can automatically generate the prefetch instructions as part of the SSR rendering. By executing the application, Qwik has runtime knowledge of which components are visible, which events the users can trigger and what code will need to be downloaded. The result is that the prefetch is an ideal set of files for this page. No action on the developers' part is required other than configuring the `renderToString()` with prefetching strategy.
42 changes: 10 additions & 32 deletions packages/docs/src/routes/docs/cheat-sheet/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,7 @@ export const Component = component$(() => {

```tsx
export function Component() {
return (
<div>
Hello world
</div>
)
return <div>Hello world</div>;
}
```

Expand All @@ -32,23 +28,17 @@ export function Component() {
export const Component = component$(() => {
return (
<>
<button onClick$={() => console.log('click')}>
Click me
</button>
<button onClick$={() => console.log('click')}>Click me</button>
</>
)
})
);
});
```

### React

```tsx
export function Component() {
return (
<button onClick={() => console.log('click')}>
Click me
</button>
)
return <button onClick={() => console.log('click')}>Click me</button>;
}
```

Expand All @@ -74,11 +64,7 @@ export const Component = component$(() => {
```tsx
export function Component() {
const [value, setValue] = useState(0);
return (
<div>
Value is: {value}
</div>
)
return <div>Value is: {value}</div>;
}
```

Expand Down Expand Up @@ -107,14 +93,10 @@ export function Counter() {
const [count, setCount] = useState(0);
return (
<>
<div>
Value is: {count}
</div>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
<div>Value is: {count}</div>
<button onClick={() => setCount(count + 1)}>Increment</button>
</>
)
);
}
```

Expand Down Expand Up @@ -153,11 +135,7 @@ export function Clock() {
}, 1000);
return () => clearInterval(interval);
});
return (
<div>
Seconds: {seconds}
</div>
)
return <div>Seconds: {seconds}</div>;
}
```

Expand Down
45 changes: 23 additions & 22 deletions packages/docs/src/routes/docs/cheat/serialization/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ title: Serialization & Serialization Boundaries
A serialization boundary occurs 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";
import { component$ } from '@builder.io/qwik';

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

Expand All @@ -25,30 +25,31 @@ export const Greeter = component$(() => {

const captureSerializable = 'serializable data';
const captureNonSerializable = Promise.resolve('nonserializable data');

return (
<button onClick$={() => {
// BEGIN onClick serialization boundary

// 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-top-level variable is allowed only if:
// - declared as `const`
// - is serializable (runtime error)
console.log(captureSerializable); // OK

// Referring 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 boundary
}}>
return (
<button
onClick$={() => {
// BEGIN onClick serialization boundary

// 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-top-level variable is allowed only if:
// - declared as `const`
// - is serializable (runtime error)
console.log(captureSerializable); // OK

// Referring 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 boundary
}}
>
click
</button>
);
// BEGIN component serialization boundary
});

```
```
19 changes: 11 additions & 8 deletions packages/docs/src/routes/docs/components/anatomy/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,16 @@ export const MyCmp = component$(async (props: MyCmpProps) => {
// Returns JSX
return (
<>
<span>Hello, {props.name} {state.count}</span>
<span>
Hello, {props.name} {state.count}
</span>
<div>Times: {state.count}</div>
<button onClick$={() => {
// This will update the local state and cause a re-render.
// Reactivity is at qwik's core!
state.count++;
}}
<button
onClick$={() => {
// This will update the local state and cause a re-render.
// Reactivity is at qwik's core!
state.count++;
}}
>
Increment
</button>
Expand Down Expand Up @@ -64,7 +67,8 @@ const MyApp = component$(() => {
<>
- With no props: <Item />
- With some props: <Item description="Item description" />
- With all props: <Item name="Hammer" quantity={3} description="Best organic hammer" price={10.0} />
- With all props:{' '}
<Item name="Hammer" quantity={3} description="Best organic hammer" price={10.0} />
</>
);
});
Expand All @@ -86,7 +90,6 @@ const Parent = () => (

In the above example, referring to the `Parent` component implies a transitive reference to the `Child` component. When the bundler is creating a chunk, a reference to `Parent` necessitates bundling `Child` as well. (`Parent` internally refers to `Child`.) These transitive dependencies are a problem because it means that having a reference to the root component will transitively refer to the remainder of the application—something which Qwik tries to avoid explicitly.


```tsx
const Child = component$(() => {
return <span>child</span>;
Expand Down
Loading

0 comments on commit 1757694

Please sign in to comment.