Typescript Berlin Meetup - Nov 2022
Frontend Engineer at Revolut
Typescript Berlin Meetup - Nov 2022
Frontend Engineer at Revolut
Making possible that they communicate between each other!
---
import ReactHeader from 'components/Header.tsx';
import SvelteForm from 'components/Form.svelte';
import VueResult from 'components/Result.vue';
import { form, saveForm } from './state'
---
<main>
<ReactHeader title="My app" />
<SvelteForm onSubmit={saveForm} />
<VueResult result={form} />
</main>
Build tool that aims to provide a faster and leaner development experience for modern web projects.
Consists of:
Vite can be extended using plugins, which are based on Rollupβs well-designed plugin interface with a few extra Vite-specific options.
$ npm add -D @vitejs/plugin-legacy
// vite.config.ts
import legacy from '@vitejs/plugin-legacy';
import { defineConfig } from 'vite';
export default defineConfig({
plugins: [
legacy({
targets: ['defaults', 'not IE 11'],
}),
],
});
$ npm add -D @vitejs/plugin-react @vitejs/plugin-vue @sveltejs/vite-plugin-svelte
// vite.config.ts
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import vue from '@vitejs/plugin-vue';
import { svelte } from '@sveltejs/vite-plugin-svelte';
export default defineConfig({
plugins: [react(), vue(), svelte()],
});
But wait β¦ What about?
---
import AstroComponent from '../components/AstroComponent.astro';
import ReactComponent from '../components/ReactComponent.tsx';
// type definition
type Props = {
title: string;
}
// Access passed-in component props, like `<X title="Hello, World" />`
const {title} = Astro.props;
// Fetch external data, even from a private API or database (SSG)
const data = await fetch('EXTERNAL_SOURCE/users').then(r => r.json());
// Read params from the url (SSR)
const product = await getProduct(Astro.params.id);
---
// render HTML with usage of props
<h1>Title is: {title}</h1>
// Mix HTML with JavaScript expressions, similar to JSX
<ul>
{data.map((item) => <li>{data.id}</li>)}
</ul>
// Render another Astro component and pass props (No JS loaded)
<AstroComponent title={title} />
// Render a framework component and pass props (JS loaded)
<ReactComponent client:load onChange={callback}/>
<style>
/* scoped to the component, other H1s on the page remain the same */
h1 { color: red }
</style>
---
import Layout from '../layouts/Layout.astro';
import Counter from '../components/Counter';
---
<Layout title="Welcome to Astro.">
<main>
<h1>Welcome to <span class="text-gradient">Astro</span></h1>
<br />
<h2><pre>no directive</pre></h2>
<p class="instructions">
<code>No JS, no interactive</code>
<Counter />
</p>
<br />
<h2><pre>client:load</pre></h2>
<p class="instructions">
<code>Loads JS as soon as possible</code>
<Counter client:load />
</p>
<br />
<h2><pre>client:idle</pre></h2>
<p class="instructions">
<code>Loads JS when rendering is over</code>
<Counter client:idle />
</p>
<br />
<h2><pre>client:visible</pre></h2>
<p class="instructions">
<code>Loads JS when button is visible by the user</code>
<Counter client:visible />
</p>
<br />
<h2><pre>client:media</pre></h2>
<p class="instructions">
<code>Loads JS when the media query (min-width: 680px) is valid</code>
</p>
<Counter client:media="(min-width: 680px)" />
<br />
<h2><pre>client:only</pre></h2>
<p class="instructions">
<code>Loads JS only in client (No SSR)</code>
<Counter client:only="react" />
</p>
</main>
</Layout>
A tiny state manager for React, React Native, Preact, Vue, Svelte, and vanilla JS. It uses many atomic stores and direct manipulation.
// store/users.ts
import { atom } from 'nanostores';
import type User from 'types';
export const users = atom<User[]>([]);
export function addUser(user: User) {
users.set([...users.get(), user]);
}
import { useStore } from '@nanostores/react';
import { users } from '../stores/users.ts';
import { UserItem } from './UserItem.tsx';
export const UserList = () => {
const list = useStore(users);
return (
<ul>
{list.map((user) => (
<UserItem key={user.id} user={user} />
))}
</ul>
);
};
<script lang="ts">
import { UserForm } from './UserForm.svelte';
import { addUser } from '../stores/users.ts';
</script>
<UserForm on:submit={user => addUser(user)} />
// pages/index.astro
---
// Astro
import Layout from 'layouts/Layout.astro';
import type { Product } from 'types';
// React
import { HighlighterWrapper, HighlighterToggle } from 'components/Highlighter';
import CategoryChart from 'components/CategoryChart';
// Svelte
import Tags from 'components/Tags.svelte';
import ProductTable from 'components/ProductTable.svelte';
// Vue
import Banner from 'components/Banner.vue';
import Overview from 'components/Overview.vue';
// fetch data
const products = await fetch('https://dummyjson.com/products')
.then((res) => res.json())
.then((res) => res.products as Product[]);
---
<Layout page="Home">
<HighlighterToggle client:only="react" />
<div class="tw-grid tw-gap-4 tw-grid-cols-3 lg:tw-grid-cols-5 md:tw-gap-10">
<HighlighterWrapper
client:idle
framework="vue"
className="tw-col-span-full"
>
<Banner client:load />
</HighlighterWrapper>
<HighlighterWrapper client:idle framework="svelte">
<Tags client:load products={products} />
</HighlighterWrapper>
<HighlighterWrapper client:idle framework="vue">
<Overview client:load products={products} />
</HighlighterWrapper>
<HighlighterWrapper client:idle framework="react" className="tw-col-span-3">
<CategoryChart client:only="react" products={products} />
</HighlighterWrapper>
<HighlighterWrapper
client:idle
framework="svelte"
className="tw-col-span-full"
>
<ProductTable client:visible products={products} />
</HighlighterWrapper>
</div>
</Layout>
// utils/state.ts
import { atom } from 'nanostores';
export const isFrameworkVisible = atom(false);
export const hiddenCategories = atom<string[]>([]);
// components/Tags.svelte
<script lang="ts">
import Chip, { Set, Text } from '@smui/chips';
import { getCategories } from 'utils/product';
import type { Product } from 'types';
import { humanize } from 'utils/string';
import { hiddenCategories } from 'utils/state';
export let products: Product[];
let categories = getCategories(products);
let selected: string[] = Array.from(categories);
function updateSelection() {
hiddenCategories.set(
categories.filter((category) => !selected.includes(category)),
);
}
</script>
<h1>Categories</h1>
<Set
chips={categories}
let:chip
filter
bind:selected
on:click={updateSelection}
>
<Chip {chip} touch>
<Text>{humanize(chip)}</Text>
</Chip>
</Set>