/* https://codepen.io/kevinpowell/full/vYvEdWG */
.cluster {
outline: 5px solid hotpink;
padding: 1rem;
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.flexible-grid {
outline: 5px solid hotpink;
padding: 1rem;
display: flex;
flex-wrap: wrap;
gap: 1rem;
}
.flexible-grid > * {
flex: 1;
}
.auto-grid {
outline: 5px solid hotpink;
padding: 1rem;
display: grid;
gap: 1rem;
grid-template-columns: repeat(auto-fit, minmax(min(10rem, 100%), 1fr));
}
.reel {
outline: 5px solid hotpink;
padding: 1rem;
display: grid;
gap: 1rem;
grid-auto-flow: column;
grid-auto-columns: 45%;
overflow-x: scroll;
scroll-snap-type: x mandatory;
scroll-padding: 1rem;
}
.reel > * {
scroll-snap-align: start;
}
.main-with-sidebar {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
gap: 1em;
max-width: 1200px;
margin-inline: auto;
}
.main-with-sidebar > :first-child {
flex-basis: 500px;
flex-grow: 9999;
}
.main-with-sidebar > :last-child {
flex-basis: 300px;
flex-grow: 1;
}
// https://medium.com/@hxu0407/master-these-8-promise-concurrency-control-techniques-to-significantly-improve-performance-5a1c199b6b3c
// 1. Promise.all: Execute in Parallel and Return Results Together
const promise1 = Promise.resolve(1);
const promise2 = Promise.resolve(2);
const promise3 = Promise.resolve(3);
Promise.all([promise1, promise2, promise3])
.then(results => {
console.log(results); // Output: [1, 2, 3]
});
// 2. Promise.allSettled: Execute in Parallel and Return All States
const promise1 = Promise.resolve(1);
const promise2 = Promise.reject("Error");
const promise3 = Promise.resolve(3);
Promise.allSettled([promise1, promise2, promise3])
.then(results => {
console.log(results);
/* Output:
[
{ status: 'fulfilled', value: 1 },
{ status: 'rejected', reason: 'Error' },
{ status: 'fulfilled', value: 3 }
]
*/
})
// 3. Promise.race: Execute in Parallel and Return the Fastest
const promise1 = new Promise(resolve => setTimeout(() => resolve("Fast"), 100));
const promise2 = new Promise(resolve => setTimeout(() => resolve("Slow"), 500));
Promise.race([promise1, promise2])
.then(result => console.log(result)); // Output: "Fast" (whichever resolves first)
// 4. Promise.any (ES2021): Execute in Parallel and Return the First Fulfilled
const promise1 = Promise.reject("Error 1");
const promise2 = new Promise(resolve => setTimeout(() => resolve("Success"), 200));
const promise3 = Promise.reject("Error 2");
Promise.any([promise1, promise2, promise3])
.then(result => console.log(result)) // Output: "Success"
.catch(error => console.log(error.errors)); // If all reject
// 5. Custom Concurrency Control Function: Limit Max Concurrent Requests
async function limitConcurrency(tasks, limit) {
const results = [];
const running = new Set();
for (const task of tasks) {
const promise = task().then(result => {
running.delete(promise);
return result;
});
running.add(promise);
results.push(promise);
if (running.size >= limit) {
await Promise.race(running);
}
}
return Promise.all(results);
// https://medium.com/@hxu0407/9-smart-ways-to-replace-if-else-in-javascript-28f82ad6dcb9
// 1. Object Mapping Instead of if-else
function getPrice(user) {
if (user.type === 'vip') {
return 'VIP Price';
} else if (user.type === 'svip') {
return 'SVIP Price';
} else if (user.type === 'vvip') {
return 'VVIP Price';
} else {
return 'Regular Price';
}
}
// better
const priceStrategy = {
vip: () => 'VIP Price',
svip: () => 'SVIP Price',
vvip: () => 'VVIP Price',
default: () => 'Regular Price'
};
function getPrice(user) {
return (priceStrategy[user.type] || priceStrategy.default)();
}
// 2. Replace Multiple Conditions with Array.includes
if (status === 'failed' || status === 'error' || status === 'rejected') {
handleError();
}
// better
const errorStatus = ['failed', 'error', 'rejected'];
if (errorStatus.includes(status)) {
handleError();
}
// 3. Chained Ternary Operators
let message;
if (score >= 90) {
message = 'Excellent';
} else if (score >= 80) {
message = 'Good';
} else if (score >= 60) {
message = 'Pass';
} else {
message = 'Fail';
}
// better
const message =
score >= 90 ? 'Excellent' :
score >= 80 ? 'Good' :
score >= 60 ? 'Pass' :
'Fail';
// 4. Logical Operators && and ||
// Replacing a simple `if`
user.isAdmin && showAdminPanel();
// Setting default values
const name = user.name || 'unnamed';
// Nullish coalescing
const count = data?.users ?? [];
// 5. Switch-Case with Pattern Matching
const actions = new Map([
[/^vip/, handleVip],
[/^admin/, handleAdmin],
[/^user/, handleUser]
]);
/*or
const actions = [
[/^vip/, handleVip],
[/^admin/, handleAdmin],
[/^user/, handleUser]
];
*/
const handleRequest = (type) => {
const action = [...actions].find(([key]) => key.test(type));
return action ? action[1]() : handleDefault();
};
// 6. Using Proxy for Conditional Interception
const handler = {
get: (target, property) => {
return property in target ? target[property] : target.default;
}
};
const services = new Proxy({
admin: () => 'Admin Service',
user: () => 'User Service',
default: () => 'Default Service'
}, handler);
// 7. Functional Approach
// Composing conditions
const isAdult = age => age >= 18;
const hasPermission = role => ['admin', 'superuser'].includes(role);
const canAccess = user => isAdult(user.age) && hasPermission(user.role);
// Usage
users.filter(canAccess).forEach(grantAccess);
// 8. State Machine Pattern
const stateMachine = {
draft: {
publish: 'published',
delete: 'deleted'
},
published: {
unpublish: 'draft',
archive: 'archived'
},
archived: {
restore: 'draft'
}
};
const changeState = (currentState, action) =>
stateMachine[currentState]?.[action] || currentState;
// 9. Use Decorators to Handle Conditional Logic
function checkPermission(target, name, descriptor) {
const original = descriptor.value;
descriptor.value = function (...args) {
if (this.user?.hasPermission) {
return original.apply(this, args);
}
throw new Error('No permission');
};
return descriptor;
}
class Document {
@checkPermission
edit() {
// Edit the document
}
}
/*
onScopeDispose - Podobně jako onWatcherCleanup, ale obecnější.
Zavolá se, když je aktuální reaktivní efektový scope (effect scope) ukončen.
Je to užitečné pro čištění zdrojů v jakémkoliv reaktivním kontextu:
*/
// 1
import { onScopeDispose, effectScope } from 'vue'
// Vytvoření izolovaného scope
const scope = effectScope()
scope.run(() => {
// Kód uvnitř scope
onScopeDispose(() => {
// Tento kód se zavolá při scope.stop()
})
})
// Později můžete ukončit scope
scope.stop()
// 2)
const scope = effectScope()
scope.run(() => {
const state = reactive({ count: 0 })
const double = computed(() => state.count * 2)
watch(() => state.count, (count) => console.log(count))
})
// Později ukončí všechny reaktivní efekty
scope.stop()
// 1) cleanup when watch is ended
import { watch, onWatcherCleanup } from 'vue'
watch(id, (newId) => {
const { response, cancel } = doAsyncWork(newId)
// `cancel` is called if `id` changes or the component unmounts
onWatcherCleanup(cancel)
})
// 2) better watch with desctruct
const { pause, resume, stop } = watch(source, (newVal, oldVal) => {
// Watch logic
});
// Pause watching
pause();
// Resume watching
resume();
// 3 watch logic, not only true/false ...
watch(reactiveObject, (newVal, oldVal) => {
// Watch logic
}, { deep: 2 });
<!-- https://play.tailwindcss.com/yyRSjWdDIv -->
<!--
https://tailwindcss.com/docs/adding-custom-styles#using-arbitrary-values
-->
<section class="m-5 *:mb-2 *:border *:text-red-400 [&_p]:text-blue-500">
<div>text1</div>
<div>text2</div>
<div>text3</div>
<div>text4</div>
<div>text5</div>
<p>Para 1</p>
<p>Para 2</p>
<div>text 6</div>
</section>
<div class="[&:nth-child(3)]:py-0">
<!-- ... -->
</div>
<ul role="list" class="space-y-4 [&>*]:rounded-lg [&>*]:bg-white [&>*]:p-4 [&>*]:shadow">
<li class="flex"> <!-- ... -->
</ul>
<ul
role="list"
class="space-y-4 [&>*]:rounded-lg [&>*]:bg-white [&>*]:p-4 [&>*]:shadow hover:[&>li:nth-child(2)>div>p:first-child]:text-indigo-500"
>
<ul class="m-5 [&>*:not(:last-child)]:text-green-500">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul
<ul class="m-5 [&>*:not(:last-child)]:after:content-[':)']">
<li>1</li>
<li>2</li>
<li>3</li>
<li>4</li>
<li>5</li>
</ul>
<div class="[--scroll-offset:56px] lg:[--scroll-offset:44px]">
<div class="[mask-type:luminance] hover:[mask-type:alpha]">
<div class="bg-[url('/what_a_rush.png')]">
When using arbitrary values, Tailwind can generally handle this ambiguity automatically based on the value you pass in:
<!-- Will generate a font-size utility -->
<div class="text-[22px]">...</div>
<!-- Will generate a color utility -->
<div class="text-[#bada55]">...</div>
Sometimes it really is ambiguous though, for example when using CSS variables:
<div class="text-[var(--my-var)]">...</div>
In these situations, you can “hint” the underlying type to Tailwind by adding a CSS data type before the value:
<!-- Will generate a font-size utility -->
<div class="text-[length:var(--my-var)]">...</div>
<!-- Will generate a color utility -->
<div class="text-[color:var(--my-var)]">...</div>
<!--
https://play.tailwindcss.com/sLrFGm1VtG
--
<!-- Via class, ale muze to chytnout i vyssi tridu, takze radsi jeste dat #ID na ten element a pres nej ve smyslu [#nejakeId.theme-light_&] -->
<section class="theme-light">
<article>
<div class="[.theme-light_&]:bg-red-200 [.theme-dark_&]:bg-gray-800">
Obsah
</div>
</article>
</section>
<!-- Přes data atribut -->
<div data-theme="dark" class="[&[data-theme='light']]:bg-red-200 [&[data-theme='dark']]:bg-gray-800">
Obsah
</div>
<!-- Nebo pro parent selector -->
<section data-theme="light">
<div class="[[data-theme='light']_&]:bg-red-200 [[data-theme='dark']_&]:bg-gray-800">
Obsah
</div>
</section>
<!--
:root {
--x: pink;
}
-->
<div class="hover:bg-[--x]"> kuku</div>
/*
Why It’s a Problem:
Direct DOM manipulation triggers reflows and repaints, slowing down rendering.
Inserting elements one by one instead of batching updates increases the number of re-renders.
Modifying styles directly forces layout recalculations.
*/
// BAD: Multiple reflows
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
document.body.appendChild(div);
}
// GOOD: Batch updates using DocumentFragment
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const div = document.createElement('div');
div.textContent = `Item ${i}`;
fragment.appendChild(div);
}
document.body.appendChild(fragment);
<!--
https://ishadeed.com/article/css-relative-colors/#adjust-the-opacity-with-color-mix
-->
<!-- works only for color from config not defined like css variables -->
<!--v2 -->
<div class="ring-msp-red-default/30"></div>
<!--v3 -->
<div class="ring-msp-red-default ring-opacity-30"></div>
<!-- Hack if color is defined like css variable in config -->
'my-red': 'var(--primary-color)', // '#ba0c2f',
<!--v2 hack -->
does not exist
<!--v3 hack -->
ring-[color-mix(in_srgb,theme(colors.my-red)_50%,transparent)]
<!--v4 -->
no hack needed, v4 is functional (read doc)
Místo načtení celé aplikace najednou můžeš načítat moduly až když jsou potřeba:
// Běžný statický import
import { heavyFunction } from './heavyModule.js';
// Dynamický import - načte se jen když je potřeba
button.addEventListener('click', async () => {
const { heavyFunction } = await import('./heavyModule.js');
heavyFunction();
});
Můžeš načítat moduly jen za určitých podmínek:
async function loadFeature(featureName) {
if (featureName === 'chart') {
const { createChart } = await import('./chartModule.js');
createChart();
} else if (featureName === 'table') {
const { createTable } = await import('./tableModule.js');
createTable();
}
}
// Místo tohoto statického importu
import HeavyComponent from '@/components/HeavyComponent.vue';
// Můžeš použít dynamický import
const HeavyComponent = defineAsyncComponent(() =>
import('@/components/HeavyComponent.vue')
);
Zmenšíš hlavní bundle a zrychlíš tak první vykreslení:
// V Nuxt 3 můžeš dynamicky importovat i stránky
const routes = [
{
path: '/',
component: () => import('./Home.vue')
},
{
path: '/dashboard',
component: () => import('./Dashboard.vue') // Načte se až při navigaci
}
]
async function loadConfigBasedOnEnvironment() {
if (process.env.NODE_ENV === 'development') {
return import('./config.dev.json');
} else {
return import('./config.prod.json');
}
}
Když změníš jeden modul, prohlížeč může znovu stáhnout jen tento modul, ne celý bundle.
Dynamické importy mohou někdy pomoct vyřešit cyklické závislosti:
// moduleA.js
export function funcA() {
console.log('Function A');
}
export async function funcThatUsesB() {
const moduleB = await import('./moduleB.js');
moduleB.funcB();
}
// moduleB.js
import { funcA } from './moduleA.js';
export function funcB() {
console.log('Function B calls:');
funcA();
}