# QRL brainstorm
## File extensions
- `.event.js`
- `qwikloader.js` always loads this. `@builder.io/core` will never runtime import `.event.js` (there are `import` statements which the tooling rewrites to QRLs.)
- `.method.js` ????
- These are needed by the Entity. more brainstorming needed here.
- `.template.js`
- Needed by `decl:template="..."` attribute. These will be used by the renderer.
- `.css.js`
- These are derived by ther rendere from the `decl:template` to load CSS on as needed basis.
```htmlembedded=
<style decl:style="QXK"> import(foo:MyItem.css) </style>
<div decl:template="foo:MyItem" class="QXK-HOST">
<span class="QXK">...</span>
</div>
```
- `MyItem.template.js`
- `MyItem.css`
- `MyItem.css`
- `MyTime.css.sub-chunkA`
- `MyTime.css.sub-chunkB`
---
```typescript=
function MyComponent() {
return (
<div class="MyClass">
<span></span>
</div>
);
}
```
```htmlembedded=
<div class="MyComponent-h MyClass">
<span class="MyComponent"></span>
<span class="MyComponent"></span>
</div>
```
---
## Style
```typescript=
import {PRIMARY, SECONDARY} from './material';
import PRIMARY from './material.css.primary';
// <style decl:style="XYZ"> class-name {...}</styl>
// PRIMARY === class-name
import from './a.css';
// PRIMARY => scoped-CSS-class.
function AComponent() {
return <md-button style={style(PRIMARY)}></md-button>
}
function BComponent() {
return <md-button class={SECONDARY}></md-button>
}
```
- `FooComponent` => `foo.component.ts`
- `foo.template.ts`
- `foo.css`
- `foo.css.primary` / `foo.primary.css`
```typescript=
(await someFunction(QRL<()=>string>`./adsf`))() => string
someFunction(`./adsf`)
```
```typescript=
import { applyStyles } from '@builder.io/qwik/internal'
```
---
```typescript=
import {onButtonClick} from 'Foo_onClick';
<button on:click={onButtonClick}>
<button on:click="????">
// Optimizer Converts above to bellow.
<button on:click={QRL`./Foo_onClick#onButtonClick`}>
```
----
```typescript=
// MyComponent.component.tsx
export function MyComponent() {}
```
```typescript=
// index.ts
export {MyComponent} from './MyComponent.component';
```
```typescript=
// MyApp.tsx
import {MyComponent} from './index';
function MyApp() {
return <MyComponent/>
}
```
```typescript=
function EvilComponent() {
return exp ? <bar/> : <foo/>
}
```
```typescript=
function CmpA() {
return (
<CmpB style="..."/>
)
}
interface SomeProps extends HTMLAttributes {}
function CmpB<SomeProps>(props: {}) {
return (
<div style="..."></div>
)
}
```
```typescript=
// MyComponent.component.tsx
export function MyComponent(props: {name: string}) {
return <div style="color: red; width: 20px">...</div>
}
```
```typescript=
// MyApp.tsx
import {MyComponent} from './MyComponent.component';
const MyComponent2 = defineComponent<{name: string}>(QRL`...`, div')
function MyApp() {
return <>
<MyComponent style="width: 40px" name="bla"/> // <-- TYPE ERROR
<MyComponent2 style="width: 40px" name="BLA"/> // WORKS
</>
}
```
[HostElements](https://www.typescriptlang.org/play?jsx=1&ssl=31&ssc=24&pln=31&pc=34#code/KYDwDg9gTgLgBAE2AYwDYEMrDgO3QW2AGcx1lsApAZQA04BvAKDjgEscZgoAzM7ASQ5R2RVsgCiqYIQ5EGzFolYA3AFzzFmuGnREiAfnVEYwnAHMANAq1xjATymHbJ9petaA2gHIIOVWjEAay8AXSdjUzdNAF8AbncSdD8NG20MPXCXcytU5wdgTMic1O9ff1Qg0MLXYpY4hWjGRsZuAFccZBhWXzgACQhjAAowKAgwInUkuwBKeSbGFvbO7pw4AEcAYQh8SBxgDgAeABUAPkGACwGYADkCYCMsyzhuZOHR8fUj2YBeE7gp6bqfrGSTSfYwY5-JgsLAwVpQVY4VqoVAAQnizUYMDsYGwwJgoJkENOcG+cEhcHcbzGEwYOgyDyKeUcjNc0TgADI4F9SX8pvEFowAPRCuAAcSwwE4UAAdDAiCBGKBILBtL5jOLJdLSestjtfODBl4ECovBZnksuj0JcApVwAEzUj4MPCEVnmaKA-44OwpWHw1YHRKrelEb4AIgAYhAIOHmcAI8gIKhoOosAhwydesAURAXXdogchcGTk1pgLldB4EmcBqbXaoPadZttrtDcbTea2h0rat69LHSMaep6K77s5Ip7Jj6-VKA+T8WldGGozG4-YpInk6m4OnM9nc-nCIWhfjS56BcLRQBBMBgOUKq9sfWq+j92D29ncUb4OBeGVCv2XBeBW4BVhaPYrHAACydi3mAjqzNCu5zgi5KljYBxAVAuB3BGADq0CoBmS56BGABCmDrtim7hkmKZQOoABGqCtMAcZlAEyCBBGMp8eGQoYVoWFag6uGEARREkaGFFUfGW4McxrHsXAnEVNxvH8YJChFueCxAA)
---
```
// Item
- Item.component.tsx // template
- Item.ts
- Item_remove.handler.ts
- Item_add.handler.ts
- User.entity.ts
- User_login.method.ts
```
```typescript=
import {Item} from './Item.component';
export function MyApp() {
return <Item/>
}
```
```typescript=
// Item_click.state.ts
export default function () {}
```
```typescript=
import * as Item_click from './Item_click.handler';
export function Item() {
return <button on:click={Item_click}>add</button>
// <button on:click="./Item_click">add</button>
// QRL 'Item_click' => 'Item_click.handler.js'
}
```
## No bundling magic breaking apart the imports:
```typescript=
function qComponent(tag:string, fn: () => any);
function qComponent(tag:string, props: any, fn: () => any);
function qComponent(fn: () => any);
function qComponent(...args[]: any[]) {
return fn;
}
// Greeter.component.tsx
const Greeter = qComponent(() => {...});
const Greeter = qComponent('div', () => {...});
export Greeter;
// Main.component.tsx
import Greeter from './Greeter.component';
function Main() {
return (
<div>
<Greeter/>
</div>
);
}
```
## Bundling magic by breaking apart the imports:
```typescript=
// Greeter.component.tsx
const Greeter = qComponent(..);
export Greeter;
// Main.component.tsx
import { jsxDeclareTemplate } from '@builder.io/qwik/internal';
// const Greeter = import('./Greeter.component');
const Greeter = jsxDeclareComponent('./some-path-123.js');
function Main() {
return (
<div>
<Greeter/>
</div>
);
}
```
```typescript=
const GreeterB = qComponent(async (props: GreeterProps, ref: any) => {
const state = await getState<GreeterComponentState>(ref);
const { name } = state;
return (
<div>
<div>
Your name:
<input value={name} on:keyup={QRL`./Greeter_input_onKeyup#?name=.target.value`} />
</div>
<span>Hello {name}!</span>
</div>
);
});
```
```typescript=
async function Greet(this: Ref, props: {name: string}) {
const salutation = await inject(this, Salutation);
const salutation = await useState(this, Salutation);
return <span>{salutation} {name}!</span>
}
inject(
Salutation,
function Greet(salutation: any, props: {name: string}) {
return <span>{salutation} {name}!</span>
}
)
async function Greet(this: Ref, props: {name: string}) {
const salutationPromise = useState(this, Salutation);
if (Build.isClient && isLoading) {
return <span>loading...</span>
} else {
await salutationPromise;
return <span>{salutation} {name}!</span>
}
}
```
## Component import transformations
Developer Code:
```typescript=
import SomeEsmImport from './some.component';
```
Internally, while bundling the module, its source is rewritten to:
```typescript=
import {jsxDeclareComponent} from '@builder.io/qwik';
const SomeEsmImport = jsxDeclareComponent(import('./some.component'));
```
While generating the JavaScript output, it’s written as:
```typescript=
import {jsxDeclareComponent} from '@builder.io/qwik';
const SomeEsmImport = jsxDeclareComponent('./abc123-hash.js', 'tag-name');
```
## Synthetic Entry Points
Developer Code:
```typescript=
// cmp.a.tsx
export default function(){...}
// cmp.b.tsx
import CmpA from './cmp.a'
export default function(){
return (
<div>
<CmpA/>
</div>
)
}
```
Output Code:
```typescript=
// @entry1.tsx (generated file)
import { jsxDeclareComponent } from '@builder.io/qwik';
export { CmpA } = jsxDeclareComponent('./cmp.a', 'a-name');
export { CmpC } = jsxDeclareComponent('./cmp.c', 'c-name');
// cmp.a.tsx
export default function(){...}
// cmp.b.tsx
import { CmpA } from '@entry1'
export default function(){
return (
<div>
<CmpA/>
</div>
)
}
```
----
`my-counter.tsx`
```typescript=
// First declare the component interface types.
export interface MyCounterProps {
step?: number;
}
export interface MyCounterState {
count: number;
}
// Next declare the component's state factory. This will be used when new component is
// being created to initialize the state. (It will not be used on rehydration.)
export const MyCounterStateFactory = qStateFactory<MyCounterProps, MyCounterState>(() => ({
count: 0,
}));
export const MyCounterView = qView<typeof MyCounter>((props) => {
const state = getState(props);
return (
<div>
<button on:click={MyCounterDecrement}>-</button>
<span>{state.count}</span>
<button on:click={MyCounterDecrement}>+</button>
</div>
);
});
// Next declare the component
export const MyCounter = qComponent<MyCounterProps, MyCounterState>({
stateFactory: MyCounterStateFactory,
template: MyCounterView,
});
// Finally declare the component's behavior (event handlers)
export const MyCounterIncrement = qHandler<typeof MyCounter>((props) => {
const state = getState(props);
state.count += props.step || 1;
markDirty(props);
});
export const MyCounterDecrement = qHandler<typeof MyCounter>((props) => {
const state = getState(props);
state.count -= props.step || 1;
markDirty(props);
});
```
```typescript=
import {MyCounter} from './my-counter';
function MyApp() {
return <MyCounter/>
}
```
REWRITE
```typescript=
import {MyCounter} from './@entry-group-123';
function MyApp() {
return <MyCounter/>
}
```
`@@entry-group-123`
```typescript=
export MyCounter from './my-counter';
```
`my-counter.js`
```typescript=
// qComponent internally calls jsxDeclareComponent
export const MyCounter = qComponent<MyCounterProps, MyCounterState>({
stateFactory: './@entry-group-123',
template: './@entry-group-123',
});
export const MyComponentView = (props) => {
const state = getState(props);
return (
<div>
<button on:click="./@my-counter-123">-</button>
<span>{state.count}</span>
<button on:click="./@my-counter-123#MyCounterDecrement">+</button>
</div>
);
}
```
------
## 1) Developer's Source Code
**my-counter.tsx**
```typescript=
export const MyCounterView = qView<MyCounter>((props) => {
const state = getState(props);
return (
<div>
<button on:click={MyCounterIncrement}>+</button>
<span>{state.count}</span>
</div>
);
});
export const MyCounterIncrement = qHandler<MyCounter>((props) => {
const state = getState(props);
state.count += props.step || 1;
markDirty(props);
});
export const MyCounter = qComponent<MyCounter>({
view: MyCounterView,
});
```
**my-app.tsx**
```typescript=
import { MyCounter } from './my-counter';
const MyAppView = qView<MyApp>(() => {
return (
<section>
<MyCounter/>
</section>
);
});
export const MyApp = qComponent<MyApp>({
view: MyAppView,
});
```
## 2) Generate Entry Files rollup will use as "input" option to start with
**entry-0**
```typescript=
export { MyCounterIncrement } from './my-counter';
```
**entry-1**
```typescript=
export { MyCounterView } from './my-counter';
```
**entry-2**
```typescript=
export { MyCounter } from './my-counter';
```
**entry-3**
```typescript=
export { MyAppView } from './my-app';
```
**entry-4**
```typescript=
export { MyApp } from './my-app';
```
## 3) Rewrite imports, after typescript to js transpiling, but before final JavaScript output
**my-counter.js**
- Rewrite local vars to dynamic imports of the generated entry paths
```typescript=
export const MyCounterView = qView((props) => {
const state = getState(props);
return (
h("div", null,
h("button", { onClick: import("entry-0#MyCounterIncrement")}, "+"),
h("span", null, state.count)
);
);
});
export const MyCounterIncrement = qHandler((props) => {
const state = getState(props);
state.count += props.step || 1;
markDirty(props);
});
export const MyCounter = qComponent({
view: import('entry-1#MyCounterView'),
});
```
**my-app.js**
- Change ESM import url to generated entry paths
```typescript=
import { MyCounter } from 'entry-2';
const MyAppView = qView(() => {
return h("section", null, h(MyCounter, null));
});
export const MyApp = qComponent({
view: import('entry-3#MyAppView'),
});
```
## 4) Output JavaScript Files, rendering changes dynamic import()s to strings
**chunk-abc.js**
```typescript=
export const MyCounterIncrement = qHandler((props) => {
const state = getState(props);
state.count += props.step || 1;
markDirty(props);
});
```
**chunk-cde.js**
```typescript=
export const MyCounterView = qView((props) => {
const state = getState(props);
return (
<div>
<button on:click="./chunk-abc#MyCounterIncrement">+</button>
<span>{state.count}</span>
</div>
);
return (
h("div", null,
h("button", { onClick: './chunk-abc#MyCounterIncrement'}, "+"),
h("span", null, state.count)
);
);
});
```
**chunk-qrs.js**
```typescript=
export const MyCounter = qComponent({
view: './chunk-cde.js#MyCounterView',
});
```
**chunk-xyz.js**
```typescript=
export const MyApp = qComponent({
view: './chunk-qrs.js#MyCounterView'
});
```
---
```typescript=
export MyTestView = qView(() => (<button on:click={MyHandle}>...</button>));
```
```typescript=
export MyTestView = qView(() => (<button on:click={QRLSSR`my-handle.js#MyHandle`}>...</button>));
```
chunkMap = {
'my-handle.js#MyHandle': './chunk-abc#click'
}
```htmlembedded=
<button on:click="./chunk-abc#click">...</button>
```
```typescript=
const qrlMap = /* @PURE */ new Map();
function h() {
const symbol = prop['on:click'];
if (DEV_MODE && isSymbol(symbol)) {
const uuid = generateUUID();
qrlMap.set(uuid, symbol);
prop['on:click'] = uuid;
}
}
export MyTestView = qView(() => (<button on:click={"UUID"}>...</button>));
```