uz
Feedback
ToCode

ToCode

Kanalga Telegramโ€™da oโ€˜tish

ื˜ื™ืคื™ื ืงืฆืจื™ื ืœืžืชื›ื ืชื™ื ืžืืช ื™ื ื•ืŸ ืคืจืง

Ko'proq ko'rsatish
1 419
Obunachilar
Ma'lumot yo'q24 soatlar
Ma'lumot yo'q7 kunlar
-530 kunlar
Postlar arxiv
ToCode
1 419
ื›ืชื‘ืชื™ ืคื” ืœืคื ื™ ื›ืžื” ื™ืžื™ื ืขืœ ื”ืฉื™ื ื•ื™ ื”ื–ื” ื‘ืจื™ืืงื˜ 19 ืฉืืžื•ืจ ืœืงืœืงืœ ืืช ืจื™ืืงื˜ ืงื•ื•ืจื™ ืื– ืœืฉืžื—ืชื ื• ื”ื—ื‘ืจื™ื ื”ืงืฉื™ื‘ื• ืœืฆืขืงื•ืช ื•ื”ืกื™ืคื•ืจ ื›ืจื’ืข ื”ื•ืงืคื https://blog.codeminer42.com/how-react-19-almost-made-the-internet-slower/

ToCode
1 419
ืคื•ื—ื“ ืืคื™ืœื• ืœื ืกื•ืช (ืกื‘ื™ื‘ืช ืชืจื’ื•ืœ) ืœื›ืชื•ื‘ ืืคืœื™ืงืฆื™ื™ืช ื•ื•ื‘ ื‘ืœื™ ืคืจื™ื™ืžื•ื•ืจืง? ืื ื™ ืคื•ื—ื“ ืืคื™ืœื• ืœื ืกื•ืช. ืžืื™ืคื” ืื ื™ ืืงื— ืืช ื›ืœ ื“ื•ื’ืžืื•ืช ื”ืงื•ื“? ืื™ืš ืื ื”ืœ ืกื˜ื™ื™ื˜ ื’ืœื•ื‘ืืœื™? ื•ืžื” ืื ื”ืงื•ื“ ื™ืกืชื‘ืš ื•ื™ืฆื ืžืฉืœื™ื˜ื”? ื‘ืคืจื•ื™ืงื˜ ืœืœืงื•ื— ืื• ื‘ืžืงื•ื ืขื‘ื•ื“ื” ืื™ืŸ ื“ื‘ืจ ื™ื•ืชืจ ื˜ื‘ืขื™ ืžืœื‘ื—ื•ืจ ืืช ื”ื˜ื›ื ื•ืœื•ื’ื™ื” ื”ืžื‘ื•ืกืกืช, ื–ืืช ืฉื™ื”ื™ื” ื”ื›ื™ ืงืœ ืœื’ื™ื™ืก ืื ืฉื™ื ืขื‘ื•ืจื”, ืœื”ื™ืขื–ืจ ื‘ Chat GPT ื‘ืฉืืœื•ืช ื•ื”ื›ื™ ื—ืฉื•ื‘ ืœื“ืขืช ืฉืœื ืžืฉื ื” ืžื” ื™ืงืจื” ืชืžื™ื“ ื™ื”ื™ื” ืžื•ืฆื. ืื ืฉื™ื ืื—ืจื™ื ื›ื‘ืจ ื›ืชื‘ื• ื™ื™ืฉื•ืžื™ื ื“ื•ืžื™ื ื‘ืจื™ืืงื˜ ื•ืœื›ืŸ ื’ื ืื ื™ ืืกืชื“ืจ. ืื‘ืœ ื‘ืคืจื•ื™ืงื˜ ืฆื“? ื‘ืคืจื•ื™ืงื˜ ืœืœื™ืžื•ื“ื™ื? ื‘ืงื•ืจืก? ืื—ืช ื”ืžื˜ืจื•ืช ืฉืœ ืคืจื•ื™ืงื˜ื™ื ื ื˜ื•ืœื™ ืกื™ื›ื•ืŸ ื”ื™ื ืœืงื‘ืœ ืžืจื—ื‘ ื‘ื˜ื•ื— ืœื”ืชื ืกื•ืช, ืžืจื—ื‘ ืฉื‘ื• ืืคืฉืจ ืœื›ืชื•ื‘ ืืคืœื™ืงืฆื™ื” ื‘ื’ื™ืฉืช Micro Services ื’ื ืื ื–ื” Overkill, ืœื”ื›ื ื™ืก ื‘ืกื™ืก ื ืชื•ื ื™ื ืžื‘ื•ื–ืจ (ืื• 5 ื‘ืกื™ืกื™ ื ืชื•ื ื™ื), ืœืขืฆื‘ ื“ืฃ ื‘ื™ืช ืชืœืช ืžื™ืžื“ื™ ืขื Three.js ื•ื›ืŸ ื’ื ืœื›ืชื•ื‘ ืืช ื” Front End ื‘ืœื™ ืืฃ ืคืจื™ื™ืžื•ื•ืจืง ื•ืืช ืฆื“ ื”ืฉืจืช ื‘ Rust. ืœื ื™ื•ื“ืข ืื™ื–ื” ืžื”ืจืขื™ื•ื ื•ืช ื”ืืœื” ื™ืขื‘ื•ื“ ืœืคืจื•ื™ืงื˜ ืฉืœื›ื ื•ื›ืžื” ืžืคืจื•ื™ืงื˜ื™ ื”ืœื™ืžื•ื“ื™ื ื”ืืœื” ื‘ืืžืช ื™ืฆืœื™ื—ื• ืœื”ืชืจื•ืžื, ืื‘ืœ ืžื” ืฉื‘ื˜ื•ื— ืฉื‘ืกื™ื•ื ื”ื›ืชื™ื‘ื” ืชื”ื™ื” ืœื›ื ื”ื‘ื ื” ื˜ื•ื‘ื” ืฉืœ ืฉื™ื˜ืช ืขื‘ื•ื“ื” ื—ื“ืฉื”, ื•ืื•ืœื™ ื—ืœืง ืžืฉื™ื˜ื•ืช ื”ืขื‘ื•ื“ื” ื”ืืœื” ื™ืขื–ืจื• ืœื›ื ื’ื ืœืคืจื•ื™ืงื˜ื™ื ืืžื™ืชื™ื™ื.

ToCode
1 419
ืขื•ื“ ื›ืžื” ื˜ื™ืขื•ื ื™ื ื ื’ื“ ื˜ื™ื™ืคืกืงืจื™ืคื˜ ื”ื˜ื™ืขื•ืŸ ื”ืจืืฉื•ืŸ ื ื’ื“ ื˜ื™ื™ืคืกืงืจื™ืคื˜ ื”ื•ื ืฉืื™ืŸ ืฆื•ืจืš ื”ื™ื•ื ืœื”ื•ืกื™ืฃ ืฉืœื‘ "ื‘ื ื™ื™ื”" ื•ืขื“ื™ืฃ ืœืฉืœื•ื— ืœื“ืคื“ืคืŸ ื™ืฉื™ืจื•ืช ืืช ื”ืงื•ื“ ืฉืื ื—ื ื• ื›ื•ืชื‘ื™ื, ื‘ืžื™ื•ื—ื“ ืžืื—ืจ ื•ื“ืคื“ืคื ื™ื ืชื•ืžื›ื™ื ื‘ ES Modules ื• Import Maps. ืื ื™ ืฉื ืืช ื”ื˜ื™ืขื•ืŸ ื”ื–ื” ื‘ืฆื“ ื›ื™ ื”ืืžืช ืฉื”ืชืจื’ืœื ื• ืœืฉืœื‘ ื”ื‘ื ื™ื™ื”. ื”ื˜ื™ืขื•ืŸ ื”ืฉื ื™ ื ื’ื“ ื˜ื™ื™ืคืกืงืจื™ืคื˜ ื™ื•ืชืจ ืžืขื ื™ื™ืŸ - ื•ื”ื•ื ืฉื˜ื™ื™ืคืกืงืจื™ืคื˜ ืคืฉื•ื˜ ืœื ืžืกืคื™ืง ื˜ื•ื‘ื” ื•ืืคื™ืœื• ื‘ืžืงืจื™ื ืคืฉื•ื˜ื™ื ืฆืจื™ื›ื™ื ืœื”ื•ืกื™ืฃ ืžืขืงืคื™ื. ืงื•ื“ ืœื“ื•ื’ืžื”:
type Table = Array<Array<number>>;

function duplicateRow(table: Table, rowIndex: number): Table {
    if ((rowIndex >= table.length) || (rowIndex < 0)) {
        throw new Error("row index out of range")
    }

    return [...table.slice(0, rowIndex), table.at(rowIndex), ...table.slice(rowIndex)];
}
ื”ืงื•ื“ ื”ื–ื” ืื™ื ื• ื˜ื™ื™ืคืกืงืจื™ืคื˜ ืชืงื ื™ ื›ื™ ื˜ื™ื™ืคืกืงืจื™ืคื˜ ืœื ื™ื•ื“ืข ืฉ at ื—ื™ื™ื‘ ืœื”ื—ื–ื™ืจ ืฉื•ืจื” ืžืชื•ืš ื”ืžืขืจืš ื›ื™ ื›ื‘ืจ ื•ื™ื“ืื ื• ืฉื”ืื™ื ื“ืงืก ื ืžืฆื ื‘ื˜ื•ื•ื— ืฉื•ืจื” ืžืขืœ. ื•ื›ืŸ ืื ื™ ื™ื›ื•ืœ ืœื”ื—ืœื™ืฃ ืืช ื” at ื‘ืกื•ื’ืจื™ื™ื ืžืจื•ื‘ืขื™ื ื•ืื– ื”ื›ืœ ื™ืชืงืžืคืœ, ื•ืื ื™ ื™ื›ื•ืœ ืœื‘ืงืฉ ืžื˜ื™ื™ืคืกืงืจื™ืคื˜ ืœื”ืชืขืœื ืžื”ืฉื’ื™ืื” ื•ืื ื™ ื™ื›ื•ืœ ืœื”ื•ืกื™ืฃ as ื•ื›ืœ ื”ื˜ืจื™ืงื™ื ื”ืืœื”, ืื‘ืœ ื–ื” ื‘ื“ื™ื•ืง ืกื•ื’ ื”ืฉื™ื ื•ื™ื™ื ืฉืื ื—ื ื• ืœื ืจื•ืื™ื ืืช ื”ืขืจืš ืฉืœื”ื. ื•ื˜ื™ืขื•ืŸ ืฉืœื™ืฉื™ ื”ื•ื ื”ืงื”ื™ืœื”. ื’ื ืื ืื ื—ื ื• ืžืฆืœื™ื—ื™ื ืœื”ืชืžื•ื“ื“ ืขื ื”ืกื™ื‘ื•ื›ื™ื•ืช ื‘ืงื•ื“ ืฉืœื ื• ื”ืจื‘ื” ืžืื•ื“ ืกืคืจื™ื•ืช ื˜ื™ื™ืคืกืงืจื™ืคื˜ ื›ื•ืœืœื•ืช ืื™ื ืกื•ืฃ ื˜ืจื™ืงื™ื ืฉืœ ื”ืฉืคื” ื›ื“ื™ ืœื™ืฆื•ืจ ื‘ืฆื•ืจื” ืื•ื˜ื•ืžื˜ื™ืช ืืช ื”ื’ื“ืจื•ืช ื”ื˜ื™ืคื•ืกื™ื ืœืคื™ ืงื•ื“ ืฉืื ื—ื ื• ื›ื•ืชื‘ื™ื. ืœื“ื•ื’ืžื” ืจื™ื“ืืงืก ื˜ื•ืœืงื™ื˜ ืœื•ืงื—ืช ืืช ืงื•ื“ ื” Reducers ื•ื™ื•ืฆืจืช ืžืžื ื• ื”ื’ื“ืจื•ืช ื˜ื™ืคื•ืกื™ื, ืื‘ืœ ืื ื™ืฉ ื˜ืขื•ืช ืงื˜ื ื” ื‘ืงื•ื“ ืื• ืืคื™ืœื• ืžื‘ื ื” ืฉื”ื•ื ืœื ื‘ื“ื™ื•ืง ืžื” ืฉื›ื•ืชื‘ื™ Redux Toolkit ื”ืชื›ื•ื•ื ื• ืื ื—ื ื• ื™ื›ื•ืœื™ื ืœืžืฆื•ื ืืช ืขืฆืžื ื• ืžื•ืœ ื”ื•ื“ืขื•ืช ืฉื’ื™ืื” ืื™ื•ืžื•ืช ืฉื™ื™ืงื— ื”ืจื‘ื” ื–ืžืŸ ืœืคืขื ื—. ืื• ืืคื•ืœื• ืฉืžื›ื ื™ืกื” ืœื”ื’ื“ืจื•ืช ื”ื˜ื™ืคื•ืกื™ื ืžืžืฉ ืืช ืฉืื™ืœืชื•ืช ื” GraphQL (ื›ืžื—ืจื•ื–ืช ืžื™ืœื” ื‘ืžื™ืœื”) ื•ืื– ืื ืื—ืจื™ ื™ืฆื™ืจืช ื”ื˜ื™ืคื•ืกื™ื ืื ื™ ืžืฉื ื” ืืคื™ืœื• ืคืกื™ืง ืื• ืจื•ื•ื— ื‘ืฉืื™ืœืชื” ืคืชืื•ื ื›ืœ ืžืขืจื›ืช ื”ื˜ื™ืคื•ืกื™ื ืžืคืกื™ืงื” ืœืขื‘ื•ื“. ืื• ืงื™ืกืœื™ ืฉืžื‘ื™ืŸ ืœื‘ื“ ืืช ืžื‘ื ื” ื”ื˜ื‘ืœืื•ืช ื•ื’ื•ื–ืจ ืžืžื ื• ื“ื™ื ืžื™ืช ื”ื’ื“ืจื•ืช ื˜ื™ืคื•ืกื™ื ื›ื“ื™ ืฉืฉืื™ืœืชื•ืช ืฉืื ื—ื ื• ื›ื•ืชื‘ื™ื ื™ื”ื™ื• Type Safe ื•ื‘ื“ืจืš ืžื‘ื™ื ืืช ื˜ื™ื™ืคืกืงืจื™ืคื˜ ืœืงืฆื”. ื›ืœ ืขื•ื“ ื–ื” ืขื•ื‘ื“ ื•ื›ืœ ื”ื’ื“ืจื•ืช ื”ื˜ื™ืคื•ืกื™ื ื”ืžื•ื–ืจื•ืช ืžื•ื›ืœื•ืช ืจืง ื‘ืชื•ืš ืงื•ื“ ื”ืกืคืจื™ื” ื”ื›ืœ ื‘ืกื“ืจ, ืื‘ืœ ื›ืžืขื˜ ื‘ื›ืœ ืกืคืจื™ื” ืžื’ื™ืข ืจื’ืข ืฉืฆืจื™ืš ืœื”ื™ื›ื ืก ืคื ื™ืžื” ืœืงื•ื“ ืฉืœื”ื ื›ื“ื™ ืœื”ื‘ื™ืŸ ืื™ืš ืœื›ืชื•ื‘ ืืช ื”ื˜ื™ืคื•ืกื™ื ื›ืš ืฉื˜ื™ื™ืคืกืงืจื™ืคื˜ ื™ื”ื™ื” ืฉืžื—. ืื ื™ ืขื“ื™ื™ืŸ ืื•ื”ื‘ ื˜ื™ื™ืคืกืงืจื™ืคื˜ ื•ื—ื•ืฉื‘ ืฉื”ื™ื ื˜ื•ื‘ื” ื™ื•ืชืจ ืžื”ืืœื˜ืจื ื˜ื™ื‘ื” ืฉืœ ื›ืชื™ื‘ื” ืœืœื ื˜ื™ืคื•ืกื™ื ืœืจื•ื‘ ื”ืคืจื•ื™ืงื˜ื™ื, ืื‘ืœ ืื™ ืืคืฉืจ ืœื”ืชืขืœื ืžื”ืžื•ืจื›ื‘ื•ืช ืฉืœ ื”ืฉืคื” ื•ื”ืืงื•ืกื™ืกื˜ื.

ToCode
1 419
ืื ื—ื ื• ื›ื‘ืจ ืœื ื—ื•ืฉื‘ื™ื ื›ื›ื” ื™ื•ืชืจ ืื—ื“ ื”ื“ื‘ืจื™ื ืฉืื”ื‘ืชื™ ื‘ืจื™ืืงื˜ ื–ื” ืฉื”ื ื›ืžืขื˜ ืืฃ ืคืขื ืœื ืฉื•ื‘ืจื™ื ืชืื™ืžื•ืช ืื—ื•ืจื” ืžื‘ื—ื™ื ืช ืงื•ื“. ื”ื ืžื‘ื™ื ื™ื ืฉื™ืฉ ืื ืฉื™ื ืฉืžืฉืชืžืฉื™ื ื‘ืžื•ืฆืจื™ื ืฉืœื”ื ื‘ืคืจื•ื“ืงืฉืŸ, ืฉืจื•ืฆื™ื ืœื”ื™ืฉืืจ ืžืขื•ื“ื›ื ื™ื ื•ืœื”ืฉืชืžืฉ ื‘ื’ื™ืจืกืื•ืช ื—ื“ืฉื•ืช ืฉืœ ืจื™ืืงื˜ ืื‘ืœ ืœื ืชืžื™ื“ ื™ื›ื•ืœื™ื ืื• ืจื•ืฆื™ื ืœืฉื ื•ืช ืืช ืกื’ื ื•ืŸ ื”ื›ืชื™ื‘ื” ืฉืœื”ื. ื•ื›ื›ื” ืœืžืจื•ืช ืฉ Functional Components ื–ื” ื”ื“ื‘ืจ, ืขื“ื™ื™ืŸ ืืคืฉืจ ืœื”ืฉืชืžืฉ ื‘ Class Components ื•ื”ื›ืœ ื™ืขื‘ื•ื“. ื•ืœืžืจื•ืช ืฉ Concurrent Mode ื–ื” ื”ื“ื‘ืจ, ืขื“ื™ื™ืŸ ืืคืฉืจ ืœื”ืคืขื™ืœ ืจื™ืืงื˜ ื‘ืœืขื“ื™ื• ื•ื”ื›ืœ ื™ืขื‘ื•ื“. ืื‘ืœ ื‘ื•ืื• ืœื ื ื˜ืขื” - ืœืฆื•ื•ืช ื”ืคื™ืชื•ื— ื™ืฉ ื“ืขื”, ื”ื“ืขื” ืฉืœื”ื ื‘ืื” ืœื™ื“ื™ ื‘ื™ื˜ื•ื™ ื‘ืฉื™ื ื•ื™ื™ื ืฉื ื›ื ืกื™ื ืœืคืจื™ื™ืžื•ื•ืจืง ื•ื”ื“ืขื” ืฉืœื”ื ื’ื ื™ื›ื•ืœื” ืœื”ืฉืชื ื•ืช. ื”ื˜ืงืกื˜ ื”ื‘ื ืžืชื•ืš PR ื‘ื ื•ืฉื Concurrent Mode ื—ืฉื•ื‘ ื‘ื”ื™ื‘ื˜ ื”ื–ื”: > This was when we were more bullish about lazy fetching being a good idea some of the time (when combined with prefetching), as opposed to our latest thinking, which is that it's almost always a bad idea. ื”ืื lazy fetching ื”ื•ื ืจืขื™ื•ืŸ ื˜ื•ื‘ ืื• ืจืข? ืื ื™ ืœื ืจื•ืฆื” ืœื”ื™ื›ื ืก ืœื“ื™ื•ืŸ ื”ื–ื” (ื™ืฉ ื“ื™ื•ืŸ ืžืขื ื™ื™ืŸ ื‘ืงื™ืฉื•ืจ). ื”ืื ื”ื˜ืจื™ื’ืจ ืœืžืฉื™ื›ืช ืžื™ื“ืข ืžืฉืจืช ืฆืจื™ืš ืœื”ื™ื•ืช ืจื™ื ื“ื•ืจ ืฉืœ ืงื•ืžืคื•ื ื ื˜ื” ืื• ืื™ื–ืฉื”ื• ื˜ืจื™ื’ืจ ื’ื“ื•ืœ ื™ื•ืชืจ ื‘ืจืžืช ื”ืืคืœื™ืงืฆื™ื”? ืฉื•ื‘, ื“ื™ื•ืŸ ืžืขื ื™ื™ืŸ, ืœื ืœื”ื™ื•ื. ืžื” ืฉื—ืฉื•ื‘ ื”ื•ื ืฉื‘ื“ื™ื•ืŸ ื”ื–ื” ืฆื•ื•ืช ื”ืžืคืชื—ื™ื ืฉืœ ืจื™ืืงื˜ ื ืงื˜ ืขืžื“ื” ื‘ืจื•ืจื” ืœืฆื“ ืื—ื“, ื•ื”ื™ื•ื ื”ื ื ื•ืงื˜ื™ื ืขืžื“ื” ื‘ืจื•ืจื” ืœืฆื“ ื”ืฉื ื™, ื›ื•ืœืœ ืฉื™ื ื•ื™ื™ื ืžืฉืžืขื•ืชื™ื™ื ื‘ืคืจื™ื™ืžื•ื•ืจืง ืฉื”ื•ืคื›ื™ื ืืช ืื—ืช ื”ื’ื™ืฉื•ืช ืœื”ืจื‘ื” ื™ื•ืชืจ ืงืฉื” ืœืžื™ืžื•ืฉ. ืขื“ื™ื™ืŸ ืžื•ืงื“ื ืœื”ื’ื™ื“ ืœืืŸ ื”ืกื™ืคื•ืจ ื”ื–ื” ื”ื•ืœืš, ืื‘ืœ ื›ืŸ ื—ืฉื•ื‘ ืœื”ืฉืื™ืจ ื‘ืจืืฉ ืฉื“ื‘ืจื™ื ื›ืืœื” ืงื•ืจื™ื ื•ื›ืฉืื ื—ื ื• ื‘ื•ื ื™ื ืืจื›ื™ื˜ืงื˜ื•ืจื” ืœื™ื™ืฉื•ื ืฉืœื ื• ืœื–ื›ื•ืจ ืฉื”ืื—ืจื™ื•ืช ืขืœื™ื ื•, ื’ื ื›ืฉืื ื“ืจื• ืงืœืืจืง ืžืฉื ื” ืืช ื“ืขืชื•.

ToCode
1 419
'my-cell': MyCell
  }
}
ื ืขื‘ื•ืจ ื‘ืฆื•ืจื” ื–ืจื™ื–ื” ืขืœ ื”ืจืขื™ื•ื ื•ืช ื”ื—ืฉื•ื‘ื™ื ืฉืœืžื“ืชื™ ืžื›ืชื™ื‘ืช ื”ื“ื•ื’ืžื”: 1. ื›ืฉืื ื™ ื‘ืชื•ืš ืงื•ืžืคื•ื ื ื˜ื” ืฉืœ "ืชื" ื•ืจื•ืฆื” ืœื”ืขื‘ื™ืจ ืคื•ืงื•ืก ื”ื“ืจืš ื”ื™ื—ื™ื“ื” ืฉืœื™ ืœืฆืืช ื”ื—ื•ืฆื” ืœืงื•ืžืคื•ื ื ื˜ื” ืฉืœ ื”ื˜ื‘ืœื” ื”ื™ื ืœืฉืœื•ื— ืื™ืจื•ืข. ืจืง ืงื•ืžืคื•ื ื ื˜ืช ื”ื˜ื‘ืœื” ื™ื›ื•ืœื” ืœืงื‘ืœ ืืช ื”ืื™ืจื•ืข ื•ืœื”ืขื‘ื™ืจ ืืช ื”ืคื•ืงื•ืก. 2. ื’ื ื›ืฉืื ื™ ืจื•ืฆื” ืœื”ืขื‘ื™ืจ ืืช ื”ืคื•ืงื•ืก ืžื” td ืœ input ืฉื ืžืฆื ื‘ืชื•ื›ื• ื™ืฉ ืœื‘ืฆืข ืืช ื”ืงืจื™ืื” ืžื”ืงื•ืžืคื•ื ื ื˜ื” ืฉืœ ื”ื˜ื‘ืœื”, ื›ื™ ื”ื™ื ื–ื• ืฉืžื’ื“ื™ืจื” ืืช ื” input ืฉื‘ืชื•ืš ื” td. 3. ืื‘ืœ ื›ืฉืื ื™ ืจื•ืฆื” ืœื”ืขื‘ื™ืจ ืืช ื”ืคื•ืงื•ืก ืžื” input ืœ td ืฉืžื›ื™ืœ ืื•ืชื• - ืคื” ืฆืจื™ืš ื›ื‘ืจ ืœืงืจื•ื ืœ focus ืžืงื•ืžืคื•ื ื ื˜ืช ื”"ืชื ื‘ื˜ื‘ืœื”" ื›ื™ ื”ื™ื ื–ืืช ืฉื™ืฆืจื” ืืช ื” td. ื‘ืงื™ืฆื•ืจ ื›ืœ ืงื•ืžืคื•ื ื ื˜ื” ื‘ Shadow DOM ืื—ืจืื™ืช ืขืœ ื”ืืœืžื ื˜ื™ื ืฉื”ื™ื ื™ื•ืฆืจืช. ืขื•ื“ ืฉืชื™ ื ืงื•ื“ื•ืช ืฉืœืžื“ืชื™ ืžื”ื“ื•ื’ืžื” ื”ื–ืืช ืขืœ ืœื™ื˜: 1. ื”ื’ื“ืจืช ืงื•ื‘ืฅ CSS ืœื›ืœ ื”ืขืžื•ื“ ืœื ืžืฉืคื™ืขื” ืขืœ ื”ืงื•ืžืคื•ื ื ื˜ื•ืช ืฉืœ lit. ื›ืœ ืงื•ืžืคื•ื ื ื˜ื” ื—ื™ื™ื‘ืช ืœื”ื’ื“ื™ืจ ืืช ืงื•ื‘ืฅ ื” CSS ื‘ืขืฆืžื”. ืžืื•ื“ ืžืขื™ื™ืฃ ื›ืฉืจื•ืฆื™ื ืœื”ื’ื“ื™ืจ ืขื™ืฆื•ื‘ ื’ืœื•ื‘ืืœื™ ื‘ืืคืœื™ืงืฆื™ื™ืช lit. 2. ืžื ื’ื ื•ืŸ ื”ื˜ืžืคืœื™ื™ื˜ืก ืฉืœ ืœื™ื˜ ื”ื•ื ืžื•ืจื›ื‘ ื•ื”ืžื•ืจื›ื‘ื•ืช ื”ื–ืืช ืœื ืชืžื™ื“ ืขื•ื‘ื“ืช ืœื˜ื•ื‘ืชื ื•. ืœื“ื•ื’ืžื” ื‘ื“ืจืš ื”ื’ื“ืจืช ื”ืชื‘ื ื™ื•ืช ื”ืจื’ื™ืœื” ืฉืœื”ื ืื™ ืืคืฉืจ ืœื”ืฉืชืžืฉ ื‘ืžืฉืชื ื” ื›ื“ื™ ืœืงื‘ื•ืข ืžื” ื™ื”ื™ื” ื” tag ื‘ืชื•ืš ื”ืชื‘ื ื™ืช. ืืคืฉืจ ืœืขืงื•ืฃ ืืช ื–ื” ืื ืžืฉืชืžืฉื™ื ื‘ืคื•ื ืงืฆื™ื” ืื—ืจืช ืฉืœื”ื ื›ื“ื™ ืœื™ืฆื•ืจ ืืช ื”ืชื‘ื ื™ืช (ืœืฉืชื™ ื”ืคื•ื ืงืฆื™ื•ืช ืงื•ืจืื™ื ื‘ืื•ืชื• ืฉื html), ืื‘ืœ ืื– ืžืื‘ื“ื™ื ืืช ื”ืจื™ืืงื˜ื™ื‘ื™ื•ืช.

ToCode
1 419
ื ื™ื”ื•ืœ ืคื•ืงื•ืก ื‘ Shadow DOM ืื—ื“ ื”ืงืฉื™ื™ื ื”ืžืจื›ื–ื™ื™ื ืฉื”ื™ื• ืœื™ ื‘ืขื‘ื•ื“ื” ืขื ืœื™ื˜ ื”ื™ื” ืœื”ื™ืคืจื“ ืžื”ืจืขื™ื•ืŸ ืฉื›ืœ ื”ื“ื‘ืจื™ื ื—ื™ื™ื ื‘ืื•ืชื• ืขื•ืœื. ืœืžืขืฉื” ื›ื‘ืจ ื”ืจื‘ื” ืฉื ื™ื ืฉืคืจื™ื™ืžื•ื•ืจืงื™ื ืฉืœ ื•ื•ื‘ ืžื ืกื™ื ืœืงื—ืช ืืช "ื”ืขื•ืœื ื”ืื—ื“" ืฉืœ ื”ื“ืคื“ืคืŸ ื•ืœื‘ื ื•ืช ื‘ืชื•ื›ื• ืงื™ืจื•ืช. ื‘ืขื‘ื•ื“ื” ืขื ืœื™ื˜ ื”ืงื™ืจ ื›ื‘ืจ ืฉื - ื•ื”ื•ื ื” Shadow DOM, ื•ืœื›ืŸ ื”ืขื‘ืจืช ื”ืžื™ื“ืข ื‘ื™ืŸ ืงื•ืžืคื•ื ื ื˜ื•ืช ื—ื™ื™ื‘ืช ืœืงืจื•ืช ืจืง ื“ืจืš ืžื ื’ื ื•ืŸ ื”ืื™ืจื•ืขื™ื. ื‘ื“ื•ื’ืžื” ื”ืคืขื ื‘ื ื™ืชื™ ื˜ื‘ืœื” ืฉืžื•ืจื›ื‘ืช ืžืงื•ืžืคื•ื ื ื˜ื” ืื—ืช ื‘ืฉื‘ื™ืœ ื”ืชื ื•ืงื•ืžืคื•ื ื ื˜ื” ืื—ืจืช ื‘ืฉื‘ื™ืœ ื”ื˜ื‘ืœื”, ื•ืจืฆื™ืชื™ ืฉืœื—ื™ืฆื” ืขืœ ื”ื—ืฆื™ื ื›ืฉืื ื™ ื‘ืคื•ืงื•ืก ืขืœ ืื—ื“ ื”ืชืื™ื ืชืฉื ื” ืืช ื”ืคื•ืงื•ืก ืœืชื ืฉืžื™ืžื™ืŸ, ืžืฉืžืืœ ืžืขืœ ืื• ืžืชื—ืช (ืœืคื™ ื”ื—ืฅ ืฉื ืœื—ืฅ). ืืคืฉืจ ืœืžืฆื•ื ืืช ื”ืงื•ื“ ื•ื”ืชื•ืฆืื” ื‘ืกื˜ืืงื‘ืœื™ืฅ ื›ืืŸ: https://stackblitz.com/edit/vitejs-vite-r29prn?file=src%2Fmy-element.ts ื•ื–ื” ื”ืงื•ื“ ื‘ื”ื“ื‘ืงื”:
import { LitElement, css, html, unsafeCSS } from 'lit'
import { customElement, property } from 'lit/decorators.js'
import litLogo from './assets/lit.svg'
import viteLogo from '/vite.svg'
import _ from 'lodash';
import style from "./index.css?inline";

@customElement('my-cell')
export class MyCell extends LitElement {
  static styles = unsafeCSS(style);
  static shadowRootOptions = {...LitElement.shadowRootOptions, delegatesFocus: true};


  handleKeypress(ev: KeyboardEvent) {
    if (ev.key === "Enter") {
      if (this.shadowRoot?.activeElement === this.shadowRoot?.querySelector('td')) {
        // td is in focus
        this.dispatchEvent(new Event('focusinside', {composed: true, bubbles: true}))
      } else {
        this.shadowRoot?.querySelector('td').focus();
      };
    } else if (ev.key === "ArrowRight") {
      this.dispatchEvent(new Event('focusright', {composed: true, bubbles: true}))
    } else if (ev.key === "ArrowLeft") {
      this.dispatchEvent(new Event('focusleft', {composed: true, bubbles: true}))
    } else if (ev.key === "ArrowUp") {
      this.dispatchEvent(new Event('focusup', {composed: true, bubbles: true}))
    } else if (ev.key === "ArrowDown") {
      this.dispatchEvent(new Event('focusdown', {composed: true, bubbles: true}))
    }
  }

  takeFocus(ev: KeyboardEvent) {
    if (ev.key === "Enter") {
      this.shadowRoot?.querySelector('td')?.focus();
    }
  }

  render() {
    return html\<td
      tabindex="1"
      @keyup=${this.handleKeypress}
      class="border-dashed border border-1 border-gray-500 focus:border-solid focus:border-green-200 focus:border-2"
    >
      <slot></slot>
    </td>
    \
  }
}

@customElement('my-table')
export class MyTable extends LitElement {
  static styles = unsafeCSS(style);

  @property({ type: Number })
  rows = 4

  @property({ type: Number })
  columns = 2

  focusUp(e: any) {
    const me = e.target;
    const tr = me.parentNode;
    const index = Array.prototype.indexOf.call(tr.children, me);
    tr.previousElementSibling.children[index].focus();
  }

  focusDown(e: any) {
    const me = e.target;
    const tr = me.parentNode;
    const index = Array.prototype.indexOf.call(tr.children, me);
    tr.nextElementSibling.children[index].focus();
  }

  render() {
    return html\
      <table class="bg-orange border-collapse"
        @focusinside=${(e: any) => e.target.firstElementChild.focus()}
        @focusright=${(e: any) => e.target.nextElementSibling.focus()}
        @focusleft=${(e: any) => e.target.previousElementSibling.focus()}
        @focusup=${this.focusUp}
        @focusdown=${this.focusDown}
      >
        <tbody>
          ${_.range(this.rows).map((i) => (
            html\
            <tr>
              ${_.range(this.columns).map((j) => (
              html\<my-cell>
                <input
                type="text"
                value="${\${i}, ${j}\}"
                class="outline-none bg-transparent border-none border-2"
              /></my-cell>\
              ))}
            </tr>
          \
          ))}
        </tbody>
      </table>
    \
  }
}

declare global {
  interface HTMLElementTagNameMap {
    'my-table': MyTable

ToCode
1 419
ื”ืคื•ื ืงืฆื™ื•ืช toReversed ื• toSorted ื‘ JavaScript ืื ื™ ืชืžื™ื“ ืื•ื”ื‘ ื›ืฉืฉืคืช ืชื›ื ื•ืช ืœื•ืงื—ืช ืขื•ื“ ืฆืขื“ ื‘ื›ื™ื•ื•ืŸ ื”ืคื•ื ืงืฆื™ื•ื ืืœื™, ื•ื–ื” ื™ื”ื™ื” ื”ืกื™ืคื•ืจ ื”ื™ื•ื ืขื ืฉืชื™ ืคื•ื ืงืฆื™ื•ืช ื—ื“ืฉื•ืช ื‘ JavaScript - ื”ืคื•ื ืงืฆื™ื•ืช toReversed ื• toSorted, ื”ื’ื™ืจืกืื•ืช ื”ืคื•ื ืงืฆื™ื•ื ืืœื™ื•ืช ืฉืœ reverse ื• sort. ื‘ืขื•ื“ ืฉื”ืคื•ื ืงืฆื™ื•ืช ื”ืžืงื•ืจื™ื•ืช ืฉื™ื ื• ืืช ืžื‘ื ื” ื”ื ืชื•ื ื™ื, ื”ื’ื™ืจืกืื•ืช ื”ื—ื“ืฉื•ืช ืฉืœื”ืŸ ืžื—ื–ื™ืจื•ืช ืœื ื• ืขื•ืชืง ืฉืœ ืžื‘ื ื” ื”ื ืชื•ื ื™ื ืžืžื•ื™ืŸ ืื• ื”ืคื•ืš. ื”ืคื•ื ืงืฆื™ื” reverse ืฉืœ JavaScript ืžื•ืคืขืœืช ืขืœ ืžืขืจืš ื•ื”ื•ืคื›ืช ืืช ื”ืื™ื‘ืจื™ื ื‘ื•:
> const x = [1, 2, 3, 4];
undefined
> x.reverse()
[ 4, 3, 2, 1 ]
ื”ื’ื™ืจืกื” ื”ื—ื“ืฉื” ืฉืœื” toReversed ืžื—ื–ื™ืจื” ืขื•ืชืง ื—ื“ืฉ ืฉืœ ื”ืžืขืจืš ืขื ื”ืื™ื‘ืจื™ื ื”ืคื•ื›ื™ื:
> const x = [1, 2, 3, 4]
undefined
> x.toReversed()
[ 4, 3, 2, 1 ]
> x
[ 1, 2, 3, 4 ]
ื ืฉื™ื ืœื‘ ืฉื›ืฉื”ืžืขืจืš ืžืงื•ื ืŸ ื”ืืœืžื ื˜ื™ื ื”ืคื ื™ืžื™ื™ื ืœื ืžื•ืขืชืงื™ื, ืœื›ืŸ:
> const x = [{a: 10}, {a: 10}, {a: 20}, {a: 30}]
undefined
> x.toReversed()
[ { a: 30 }, { a: 20 }, { a: 10 }, { a: 10 } ]
> x.toReversed()[0].a = 40
40
> x
[ { a: 10 }, { a: 10 }, { a: 20 }, { a: 40 } ]
ืื ื‘ืžืงื•ื ื”ื™ืคื•ืš ืื ื—ื ื• ืจื•ืฆื™ื ืœืžื™ื™ืŸ ื ื•ื›ืœ ืœืงืจื•ื ืœ toSorted, ืฉื”ื™ื ื”ื’ื™ืจืกื” ื”ืคื•ื ืงืฆื™ื•ื ืืœื™ืช ืฉืœ sort. ื›ืžื• sort ื’ื toSorted ื™ื›ื•ืœื” ืœืงื‘ืœ ืคื•ื ืงืฆื™ื™ืช ืžื™ื•ืŸ ืื• ืœืžื™ื™ืŸ ืœืคื™ ืกื“ืจ ืžื™ืœื•ื ื™:
> const values = [1, 10, 21, 2];
undefined

> values.toSorted()
[ 1, 10, 2, 21 ]

> values.toSorted((a, b) => a - b)
[ 1, 2, 10, 21 ]
ืืคืฉืจ ืœื—ืฉื•ื‘ ืขืœ ืฉืชื™ื”ืŸ ื‘ืชื•ืจ ื’ื™ืจืกื” ืžื”ื™ืจื” ื•ื‘ืจื•ืจื” ื™ื•ืชืจ ืฉืœ array.slice().reverse() ื• array.slice().sort:
> x.slice().reverse()
[ 9, 1, 2, 10 ]
> x
[ 10, 2, 1, 9 ]

> x.slice().sort()
[ 1, 10, 2, 9 ]
> x
[ 10, 2, 1, 9 ]

ToCode
1 419
ื—ืžื™ืฉื” ื˜ื™ืคื™ื ืœ Pair Programmning ื™ืขื™ืœ ื™ื•ืชืจ ืชื›ื ื•ืช ื‘ืฆื•ื•ืช ื™ื›ื•ืœ ืœืขื–ื•ืจ ืœื ื• ืœื›ืชื•ื‘ ืงื•ื“ ื˜ื•ื‘ ื™ื•ืชืจ ื•ืžื”ืจ ื™ื•ืชืจ, ืื‘ืœ ื’ื ื™ื›ื•ืœ ื‘ืงืœื•ืช ืœื”ืฉืชื‘ืฉ. ื”ืžืคืชื— ืœื”ืฆืœื—ื”, ืื ื›ื™ ืงืฉื” ืžืื•ื“ ืœื™ื™ืฉื•ื ื”ื•ื ื‘ื—ื™ืจื” ื˜ื•ื‘ื” ืฉืœ ื”ืฉื•ืชืคื™ื ืœืคืจื•ื™ืงื˜. ื”ื ื” ื›ืžื” ื˜ื™ืคื™ื ืฉืขื•ื–ืจื™ื ืœื™ ืœื–ื”ื•ืช ืื ืฉื™ื ืฉื›ื“ืื™ ืœื›ืชื•ื‘ ืื™ืชื ืงื•ื“, ื•ืœื—ืœื•ืคื™ืŸ ืื ืฉื™ื ืฉืขื“ื™ืฃ ืœื›ืœ ื”ืฆื“ื“ื™ื ืฉื ืขื‘ื•ื“ ื‘ื ืคืจื“: 1. ื‘ื—ืจื• ื—ื‘ืจ ืื• ื—ื‘ืจื” ืขื ืจืงืข ืฉื•ื ื” ืžืฉืœื›ื. ื”ืžื˜ืจื” ืฉืœ Pair Programming ื”ื™ื ืœื ืœื›ืชื•ื‘ ืงื•ื“ ื›ืžื” ืฉื™ื•ืชืจ ืžื”ืจ ืืœื ืœื“ื‘ืจ ืขืœ ื”ื“ื‘ืจื™ื ื”ืžืฉืžืขื•ืชื™ื™ื ื‘ืชื”ืœื™ืš ื”ืคื™ืชื•ื—. ื›ื›ืœ ืฉื™ืฉ ืคืขืจ ื‘ืจืงืข ืฉืœื›ื ืืคืฉืจ ื™ื”ื™ื” ืœืงื‘ืœ ื ืงื•ื“ืช ืžื‘ื˜ ื ื•ืกืคืช ื•ืžืขื ื™ื™ื ืช ืขืœ ื”ืืจื›ื™ื˜ืงื˜ื•ืจื”. 2. ื‘ื—ืจื• ื˜ื›ื ื•ืœื•ื’ื™ื•ืช ืื•ืชืŸ ืœืคื—ื•ืช ืื—ื“ ื”ืฆื“ื“ื™ื ืžื‘ื™ืŸ ืื• ืžื‘ื™ื ื” ื”ื™ื˜ื‘. ื”ืžื˜ืจื” ืฉืœ Pair Programming ื”ื™ื ื”ื“ื™ื•ืŸ, ืื– ืื ื—ื ื• ืจื•ืฆื™ื ืœืฆืžืฆื ื–ืžื ื™ Debug ื•ื–ืžื ื™ ื—ื™ืคื•ืฉ ื‘ืื™ื ื˜ืจื ื˜. 3. ืขืฉื• ืฉื™ืขื•ืจื™ ื‘ื™ืช - ืœื ืฆืจื™ืš ืœื›ืชื•ื‘ ื™ื—ื“ ืืช ื›ืœ ื”ืงื•ื“. ื ืกื• ืœื”ื—ืœื™ื˜ ื™ื—ื“ ืขืœ ื”ืืจื›ื™ื˜ืงื˜ื•ืจื”, ืœืžืžืฉ ื™ื—ื“ ืืช ื”ื—ืœืงื™ื ื”ืงืฉื™ื ื•ื”ื—ืฉื•ื‘ื™ื ืฉืœ ื”ืคืจื•ื™ืงื˜, ื•ืื– ืœื”ืชืงื“ื ื‘ื ืคืจื“ ื‘ื—ืœืงื™ื ืฉืœื ื“ื•ืจืฉื™ื ืžื—ืฉื‘ื”. 4. ื”ืงืฉื™ื‘ื• ืœืฆื“ ื”ืฉื ื™ ื’ื (ื•ื‘ืžื™ื•ื—ื“) ื›ืฉื ืฉืžืข ืฉื”ื ืื•ืžืจื™ื ืฉื˜ื•ื™ื•ืช - ื–ื•ื›ืจื™ื ืฉื”ืชื—ืœื ื• ืขื ื—ื‘ืจ ืื• ื—ื‘ืจื” ืขื ืจืงืข ืฉื•ื ื” ืžืฉืœื ื•? ื–ื” ืื•ืžืจ ืฉื—ืœืง ืžื”ื“ื‘ืจื™ื ืฉื ืจืื™ื ืœื ื• ืžื•ื‘ื ื™ื ืžืืœื™ื”ื ื™ื”ื™ื• ืขื‘ื•ืจื ื—ื“ืฉื™ื ื•ืžืคืชื™ืขื™ื, ื•ื—ืœืง ืžื”ื“ื‘ืจื™ื ืฉื ืจืื™ื ืœื”ื ืžื•ื‘ื ื™ื ืžืืœื™ื”ื ื™ื”ื™ื• ืœื ื• ื—ื“ืฉื™ื ื•ืžืคืชื™ืขื™ื. ืื™ืŸ ืœื›ื ื›ืจื’ืข ืืช ื”ื›ืœื™ื ืœื”ื‘ื“ื™ืœ ื‘ื™ืŸ ื”ืฉื˜ื•ื™ื•ืช ืœื“ื‘ืจื™ ื”ื—ื•ื›ืžื” ืฉืœ ื”ืฆื“ ื”ืฉื ื™ ื›ื™ ื”ื’ืขืชื ืžืขื•ืœืžื•ืช ืฉื•ื ื™ื, ื•ืœื›ืŸ ื”ื™ื• ืžื•ื›ื ื™ื ืœื”ืงืฉื™ื‘ ื•ืœื ืกื•ืช ืจืขื™ื•ื ื•ืช. 5. ื’ื™ื˜ ืกื˜ืืฉ ื”ื•ื ื—ื‘ืจ - ื—ืœืง ืžื”ืžืฉื—ืง ืฉืœ ืœืขื‘ื•ื“ ื‘ื™ื—ื“ ื–ื” ืœื”ื™ื—ืฉืฃ ืœืจืขื™ื•ื ื•ืช ื—ื“ืฉื™ื ืฉืœื ื”ื™ื™ืชื ืžื ืกื™ื ืื ื”ื™ื™ืชื ืœื‘ื“. ื—ืœืง ืžื”ืจืขื™ื•ื ื•ืช ื”ืืœื” ื˜ื•ื‘ื™ื, ื—ืœืง ื’ืจื•ืขื™ื ื•ื—ืœืง ืœื ืžืกืคื™ืง ืžืœื•ื˜ืฉื™ื. ืื ื™ ืžืฉืชื“ืœ ืœืงื‘ื•ืจ ืžื”ืจ ืขื git restore ืืช ื”ืจืขื™ื•ื ื•ืช ื”ื’ืจื•ืขื™ื, ืื‘ืœ ืืช ื”ืœื ืžืœื•ื˜ืฉื™ื ืœื”ืฉืื™ืจ ื‘ืฆื“ ืขื git stash. ื™ื•ื ืื—ื“ ืื•ืœื™ ื™ื”ื™ื” ื–ืžืŸ ืœื—ืงื•ืจ ืื•ืชื ืฉื•ื‘. ืื• ืฉืœื. ื•ื–ื” ื‘ืกื“ืจ. ื™ืฉ ืœื›ื ื˜ื™ืคื™ื ื ื•ืกืคื™ื ืฉืขื‘ื“ื•? ืืฉืžื— ืœืฉืžื•ืข ื‘ืชื’ื•ื‘ื•ืช ืคื” ืื• ื‘ื˜ืœื’ืจื.

ToCode
1 419
ืขื“ื›ื•ืŸ ืื™ืžื’'ื™ื ืื•ื˜ื•ืžื˜ื™ ืขื Watchtower ื ื›ื•ืŸ, ืื ื—ื ื• ืœื ืืžื•ืจื™ื ืœื”ืจื™ืฅ ืžืขืจื›ืช ืคืจื•ื“ืงืฉืŸ ืขื Docker Compose. ื ื›ื•ืŸ, ื”ื•ื ืœื ื›ื–ื” ื˜ื•ื‘ ื‘ื”ื•ืกืคืช ืขื•ื“ ืงื•ื ื˜ื™ื™ื ืจื™ื, ื‘ื ื™ื”ื•ืœ ื”ืงื•ื ื˜ื™ื™ื ืจื™ื ืฉืจืฆื™ื ื•ื‘ื›ืœ ื”ื“ื‘ืจื™ื ืฉืงื•ื‘ืจื ื˜ืก ื•ื“ื•ืžื™ื• ื™ื•ื“ืขื™ื ืœืขืฉื•ืช. ืื‘ืœ ืื™ ืืคืฉืจ ืœื”ืชื•ื•ื›ื— ืขื ื”ืคืฉื˜ื•ืช ืฉืœื• ื•ืœืคืขืžื™ื ื›ืฉื”ืคืจื•ื™ืงื˜ ืงื˜ืŸ ื“ื•ืงืจ ืงื•ืžืคื•ื– ื›ืŸ ื™ื›ื•ืœ ืœืชืช ืคื™ืชืจื•ืŸ ืกื‘ื™ืจ, ื’ื ืื ื–ืžื ื™. ื•ืื ืื ื—ื ื• ื›ื‘ืจ ืžืจื™ืฆื™ื ืžืขืจื›ืช ืขื Docker Compose, ืžื“ื™ ืคืขื ืื ื—ื ื• ืฆืจื™ื›ื™ื ื’ื ืœื”ืขืœื•ืช ื’ื™ืจืกื” ื—ื“ืฉื” ืฉืœ ืื—ื“ ื”ืื™ืžื’'ื™ื. ื‘ื“ื™ื•ืง ื‘ืฉื‘ื™ืœ ื–ื” ื ื•ืฆืจ Watchtower. ืœ Watchtower ื™ืฉ ืชืคืงื™ื“ ืื—ื“ ืคืฉื•ื˜ ื•ืฉื ื”ืงืกื ืฉืœื• - ืคืขื ื‘ X ื–ืžืŸ (ื›ืžื” ืฉืชื—ืœื™ื˜ื•) ื”ื•ื ืžืชื—ื‘ืจ ืœ Registry, ืžื—ืคืฉ ื’ื™ืจืกืื•ืช ื—ื“ืฉื•ืช ืฉืœ ื”ืื™ืžื’'ื™ื ื•ืื ื”ื•ื ืžื•ืฆื ื”ื•ื ืžื•ืจื™ื“ ืืช ื”ื’ื™ืจืกืื•ืช ื”ื—ื“ืฉื•ืช ื•ืžืขืœื” ืžื—ื“ืฉ ืงื•ื ื˜ื™ื™ื ืจื™ื ืขื ืื•ืชืŸ ื’ื™ืจืกืื•ืช ื—ื“ืฉื•ืช. ื–ื” ืื•ืžืจ ืฉืžืกืคื™ืง ืœื“ื—ื•ืฃ ืื™ืžื’' ืœ Registry ื‘ืฉื‘ื™ืœ ืœืขื“ื›ืŸ ืžื›ื•ื ื” ืจืฆื” ื•ื–ื” ื›ื‘ืจ ื˜ื•ื‘. ืื™ืš ื–ื” ืขื•ื‘ื“? ื™ื—ืกื™ืช ืคืฉื•ื˜. Watchtower ื”ื•ื ืกืจื‘ื™ืก ืฉืื ื—ื ื• ืžื•ืกื™ืคื™ื ืœ docker-compose.yml, ืืคืฉืจ ื‘ื ื•ืกืฃ ืœืกืจื‘ื™ืก ืฉืœื ื• ืื• ื‘ืงื•ืžืคื•ื– ืื—ืจ ืœื’ืžืจื™:
version: "3"
services:
  cavo:
    image: ynonp/myapp:latest
    ports:
      - "443:3443"
      - "80:3080"
  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --interval 30
ื›ืŸ ืฆืจื™ืš ืœืฉื™ื ืœื‘ ืœ-3 ื ืงื•ื“ื•ืช ืฉืืคืฉืจ ืœื™ืคื•ืœ ื‘ื”ืŸ: 1. ืื ื”ืื™ืžื’' ืฉืžื•ืจ ื‘ืจื’ื™ืกื˜ืจื™ ืคืจื˜ื™ ืื– ืฆืจื™ืš ืœื”ืขื‘ื™ืจ ืคื ื™ืžื” ืœืชื•ืš ื”ืงื•ื ื˜ื™ื™ื ืจ ืฉืœ watchtower ืืช ืคืจื˜ื™ ื”ื”ืชื—ื‘ืจื•ืช, ื‘ื“ืจืš ื›ืœืœ ื‘ืฆื•ืจืช ืžื™ืคื•ื™ ื”ืงื•ื‘ืฅ config.json ืฉืœ ื“ื•ืงืจ ืคื ื™ืžื” ืœืชื•ืš ื”ืงื•ื ื˜ื™ื™ื ืจ. 2. ื”ืื™ื ื˜ืจื•ื•ืœ ืงื•ื‘ืข ื›ืœ ื›ืžื” ื–ืžืŸ ืฆืจื™ืš ืœื‘ื“ื•ืง ืื ืงื™ื™ืžืช ื’ื™ืจืกื” ื—ื“ืฉื” ืฉืœ ื”ืื™ืžื’'. ื‘ืจื™ืจืช ื”ืžื—ื“ืœ ื”ื™ื ืคืขื ื‘ื™ื•ื ืื– ื‘ืฉื‘ื™ืœ ืžื ื’ื ื•ืŸ ืฉืœ ื“ื™ืคืœื•ื™ืžื ื˜ ื‘ CI/CD ื›ื“ืื™ ืœื”ื•ืจื™ื“ ืืช ื–ื”. ื”ืžืกืคืจ 30 ื‘ื“ื•ื’ืžื” ืžืฆื™ื™ืŸ 30 ืฉื ื™ื•ืช. 3. ืื ืœื ื›ืชื‘ืชื ืื—ืจืช ื” watchtower ื™ืขื“ื›ืŸ ืืช ื›ืœ ื”ืื™ืžื’'ื™ื ื‘ื›ืœ ื”ืงื•ื ื˜ื™ื™ื ืจื™ื ืฉืจืฆื™ื ืขืœ ื”ืžื›ื•ื ื”. ืืคืฉืจ ืœืกื ืŸ ืงื•ื ื˜ื™ื™ื ืจื™ื ืื ื ืขื‘ื™ืจ ืื—ืจื™ ื”ืื™ื ื˜ืจื•ื•ืœ ืืช ืฉื ื”ืงื•ื ื˜ื™ื™ื ืจ ืฉืื ื—ื ื• ืจื•ืฆื™ื ืœืขื“ื›ืŸ (ืฉื™ืžื• ืœื‘ ืฉื–ื” ืฉื ื”ืงื•ื ื˜ื™ื™ื ืจ ืœื ืฉื ื”ืกืจื‘ื™ืก ื‘ืงื•ืžืคื•ื–), ืื• ืฉื™ื˜ื” ื™ื•ืชืจ ืคืฉื•ื˜ื” ืœื“ืขืชื™ ื”ื™ื ืœื”ื’ื“ื™ืจ label ืขืœ ื›ืœ ืงื•ื ื˜ื™ื™ื ืจ ืฉืฆืจื™ืš ืขื“ื›ื•ืŸ. ื ืฉื™ื ืœื‘ ืฉืื ื™ืฉ ืœื ื• ืžืกืคืจ ืคืจื•ื™ืงื˜ื™ื ืฉื•ื ื™ื ืขื ืงื‘ืฆื™ docker-compose ืฉื•ื ื™ื ืื– ืขื“ื™ื™ืŸ watchtower ืฉืœ ืื—ื“ ืขืฉื•ื™ ืœืฉื“ืจื’ ืงื•ื ื˜ื™ื™ื ืจื™ื ืฉืœ ื”ืคืจื•ื™ืงื˜ ื”ืฉื ื™. ืกืš ื”ื›ืœ ืฉื™ืœื•ื‘ ืฉืœื•ืฉืช ื”ืกืขื™ืคื™ื ืžื‘ื™ื ืื•ืชื ื• ืœ docker-compose.yml ืฉื ืจืื” ื‘ืขืจืš ื›ืš:
services:
  db:
    image: postgres:16.3
    volumes:
      - ./tmp/db:/var/lib/postgresql/data
    environment:
      POSTGRES_PASSWORD: ${DBPASSWORD}

  watchtower:
    image: containrrr/watchtower
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
      - /home/ynon/.docker/config.json:/config.json
    command: --interval 30 --label-enable

  web:
    image: my.private.registry.com/webapp:latest
    labels:
      com.centurylinklabs.watchtower.enable: true
    environment:
      DATABASE_PASSWORD: ${DBPASSWORD}
      DATABASE_HOST: db
    ports:
      - "3000:3000"
    depends_on:
      - db

ToCode
1 419
ืขื›ืฉื™ื• ื”ืคืขื™ืœื• ืžื—ื“ืฉ ืืช ื”ืฉืจืช ื‘ืฉื ื™ ื—ืœื•ื ื•ืช - ื‘ื—ืœื•ืŸ ืื—ื“ ื ืคืขื™ืœ ./bin/vite dev ื•ื‘ื—ืœื•ืŸ ืฉื ื™ ./bin/rails s. ืื ื”ื›ืœ ื”ืœืš ื›ืžื• ืฉืฆืจื™ืš ืชื•ื›ืœื• ืœื”ื™ื›ื ืก ืœ localhost:3000 ื•ืœืจืื•ืช ืืช ื”ืงื•ืžืคื•ื ื ื˜ื” ื•ื‘ื ื•ืกืฃ ืชื•ื›ืœื• ืœืฉื ื•ืช ืืช ืงื•ื“ ื”ืงื•ืžืคื•ื ื ื˜ื”, ืœืฉืžื•ืจ ื•ืœืจืื•ืช ืืช ื”ืขืžื•ื“ ื‘ื“ืคื“ืคืŸ ืžืชืขื“ื›ืŸ. ื‘ืฉื‘ื™ืœ ืœืจื ื“ืจ ืงื•ืžืคื•ื ื ื˜ื” ืื—ืจืช ืœืคื™ ื”ืขืžื•ื“ ืื ื™ ืžืขื“ื™ืฃ ืœื›ืชื•ื‘ ืงืฆืช ืงื•ื“ JavaScript ืฉื™ืกืชื›ืœ ื‘ืขืžื•ื“, ื™ื˜ืขืŸ ืงื•ืžืคื•ื ื ื˜ื•ืช ื‘ืฆื•ืจื” ื“ื™ื ืžื™ืช ืœืคื™ data attribute ืฉืœ ืืœืžื ื˜ื™ื ื•ื™ืืชื—ืœ ืงื•ืžืคื•ื ื ื˜ื•ืช ืืœื”. ืื ื™ ืžืฉื ื” ืืช ืฉื ื”ืงื•ื‘ืฅ ื”ืจืืฉื™ ืž application.js ืœ application.jsx ื•ื›ื•ืชื‘ ื‘ื• ืืช ื”ืชื•ื›ืŸ ื”ื‘ื:
// file: app/frontend/entrypoints/application.jsx

import React from 'react';
import { createRoot } from 'react-dom/client';

async function renderAll() {
  const reactEntrypoints = document.querySelectorAll('.react');
  for (const el of reactEntrypoints) {
    const componentName = el.dataset.component;
    const Component = (await import(\../components/${componentName}.tsx\)).default;

    const root = createRoot(el);

    const dataprops = el.dataset.props;
    const props = dataprops ? JSON.parse(dataprops) : {};

    root.render(<Component {...props} />)
  }
}
  
renderAll();
ื’ื ืืช ืงื•ื“ ื”ืงื•ืžืคื•ื ื ื˜ื” ืื ื™ ืžืขื“ื›ืŸ ื›ื™ ืืคืฉืจ ืœื”ื•ืจื™ื“ ืžืฉื ืืช ื” render (ื”ื•ื ืงื•ืจื” ื‘ืงื•ื“ ื”ืจืืฉื™) ื•ืœื›ืŸ ื”ืงื•ื‘ืฅ Home.tsx ืžื›ื™ืœ ืขื›ืฉื™ื• ืจืง ืืช ื–ื”:
import React from 'react';

export default function Home({text}: {
  text: string
}) {
  return <div>
      <h1>{text}</h1>
      <a href="/about">About Page</a>
    </div>
}
ื•ืœืกื™ื•ื ืื ื™ ืžืขื“ื›ืŸ ืืช ื” View ื‘ืงื•ื‘ืฅ app/views/home/index.html.erb ื›ื“ื™ ืœื™ืฆื•ืจ ืืช ื”ืงื•ืžืคื•ื ื ื˜ื”:
<div
  class="react"
  data-component="Home"
  data-props='<%= {text: "hello"}.to_json %>'
></div>
ืฉื™ืžื• ืœื‘ ืฉื” Properties ืœืงื•ืžืคื•ื ื ื˜ื” ื›ืชื•ื‘ื™ื ื›ืืŸ ื‘ View, ื–ื” ืื•ืžืจ ืฉื ื•ื›ืœ ื‘ืงืœื•ืช ืœื”ืขื‘ื™ืจ ืื•ืชื ืžื” Controller. ืจืง ื‘ืฉื‘ื™ืœ ื”ืžืฉื—ืง ืื ื™ ืžื•ืกื™ืฃ ื“ืฃ ื ื•ืกืฃ ืœืืชืจ. ื‘ืงื•ื‘ืฅ app/controllers./home_controller.rb ืื ื™ ืžื•ืกื™ืฃ ืขื•ื“ ืคื•ื ืงืฆื™ื”:
class HomeController < ApplicationController
  def index
  end

  def about    
  end
end
ื‘ืชื™ืงื™ื™ืช frontend/components ืื ื™ ื™ื•ืฆืจ ืงื•ืžืคื•ื ื ื˜ื” ื ื•ืกืคืช ื‘ืฉื About.tsx:
// file: app/frontend/components/About.tsx

import React from 'react';

export default function About() {
  return <p>About Us</p>
}
ื•ื‘ืงื•ื‘ืฅ app/views/home/about.html.erb ืื ื™ ื›ื•ืชื‘ ืืช ืคืจื˜ื™ ื”ืงื•ืžืคื•ื ื ื˜ื”:
<div
  class="react"
  data-component="About"
></div>
ื•ืœืกื™ื•ื ื‘ืงื•ื‘ืฅ config/routes.rb ืื ื™ ืžื•ืกื™ืฃ ืืช ื”ื ืชื™ื‘:
Rails.application.routes.draw do
  root to: 'home#index'
  get '/about', to: 'home#about'
end
ืขื›ืฉื™ื• ืืคืฉืจ ืœืขื‘ื•ืจ ื‘ื™ืŸ ืฉื ื™ ื”ื“ืคื™ื ื•ืœืจืื•ืช ืฉื›ืœ ื›ื ื™ืกื” ืœื“ืฃ ืžืฆื™ื’ื” ืืช ื”ืงื•ืžืคื•ื ื ื˜ื” ืฉืžืชืื™ืžื” ืœื•. ืขื•ื“ ืกืคืจื™ื•ืช ืžื•ืžืœืฆื•ืช ื™ืฉ ืขื•ื“ ืžืกืคืจ ืกืคืจื™ื•ืช ืฉืœืคืขืžื™ื ืื ื™ ืžืฉืœื‘ ืฉื”ื•ืคื›ื•ืช ืืช ื”ื—ื™ื‘ื•ืจ ื‘ื™ืŸ ืจื™ืืงื˜ ืœืจื™ื™ืœืก ืœืืคื™ืœื• ื™ื•ืชืจ ืžื•ืฆืœื—: 1. ื”ืกืคืจื™ื” js-from-routes ืžื—ื‘ืจืช ื‘ื™ืŸ ื” Routes ืฉืžื•ื’ื“ืจื™ื ื‘ืจื™ื™ืœืก ื‘ืชื•ืจ ืคื•ื ืงืฆื™ื•ืช ืœ JavaScript. 2. ื”ืกืคืจื™ื” typesfromserializers ื™ื•ื“ืขืช ืœื™ื™ืฆืจ ืžืžืฉืงื™ ื˜ื™ื™ืคืกืงืจื™ืคื˜ ื™ืฉื™ืจื•ืช ืžืชื•ืš Serializers. ืกืจื™ืืงืœื™ื™ื–ืจื™ื ืœืžื™ ืฉืœื ืžื›ื™ืจ ื–ื” ืžื ื’ื ื•ืŸ ืจื™ื™ืœืกื™ ืฉืงื•ื‘ืข ืื™ืš ืžื•ื“ืœ ื™ื”ืคื•ืš ืœ JSON. ืขื ื”ืกืคืจื™ื” ื”ื–ืืช ื™ืฉ ืœื ื• ืื•ื˜ื•ืžื˜ื™ืช ื˜ื™ืคื•ืกื™ ื˜ื™ื™ืคืกืงืจื™ืคื˜ ืฉืžืชืื™ืžื™ื ืœื›ืœ ื” JSON-ื™ื ืฉืื ื—ื ื• ืฉื•ืœื—ื™ื ืžืจื™ื™ืœืก (ื‘ื™ืŸ ืื ื‘ืชื•ืจ props ืœืงื•ืžืคื•ื ื ื˜ื•ืช ืื• ื“ืจืš ื” API).

ToCode
1 419
ืžื‘ื ื” ืคืจื•ื™ืงื˜ Rails, React ื• TypeScript ืื ื—ื ื• ื‘ 2024, ืจื™ื™ืœืก ืขื“ื™ื™ืŸ ืฉื•ื•ื” ืืช ื”ืžืืžืฅ ื•ืจื™ืืงื˜ ื”ืคื›ื” ืœืกืคืจื™ื™ืช ื” UI ื”ื“ื™ืคื•ืœื˜ื™ืช ืฉืœ ืžืคืชื—ื™ื ืจื‘ื™ื, ื›ืžื•ื‘ืŸ ื‘ืฉื™ืœื•ื‘ ื˜ื™ื™ืคืกืงืจื™ืคื˜. ื™ืฉ ื”ืžื•ืŸ ืืคืฉืจื•ื™ื•ืช ืœืฉื™ืœื•ื‘ ืฉืœื•ืฉืช ื”ื˜ื›ื ื•ืœื•ื’ื™ื•ืช ื”ืืœื” ื™ื—ื“ ื•ืื ื™ ืจื•ืฆื” ืœื”ืจืื•ืช ื›ืืŸ ืฉื™ื˜ื” ืื—ืช ืฉืขื‘ื“ื” ื‘ืฉื‘ื™ืœื™ ื“ื™ ื˜ื•ื‘. ืจื™ื™ืœืก ืื ื™ ืžืชื—ื™ืœ ื‘ื™ืฆื™ืจืช ืคืจื•ื™ืงื˜ ืจื™ื™ืœืก 7 ื—ื“ืฉ ืขื:
$ rails new  --skip-javascript .
ืœืžืจื•ืช ืฉื™ืฉ ื‘ืจื™ื™ืœืก ืžื ื’ื ื•ืŸ ืœืขื‘ื•ื“ื” ืขื JavaScript (ืืคื™ืœื• ืฉื ื™ื™ื), ืื ื™ ืžืขื“ื™ืฃ ืืช vite ื•ืœื›ืŸ ืื ื™ ืžืชืงื™ืŸ ืืช ื”ื’'ื vite-ruby ืœืคื™ ื”ื•ืจืื•ืช ื”ื”ืชืงื ื” ืฉืœื”ื. ืžืชื•ืš ืชื™ืงื™ื™ืช ื”ืคืจื•ื™ืงื˜ ืื ื™ ื›ื•ืชื‘:
bundle add 'vite_rails'
bundle exec vite install
ื•ืื– ืืคืฉืจ ืœื ืกื•ืช ืœื”ืคืขื™ืœ ืืช ืฉืจืช ื”ืคื™ืชื•ื—:
$ ./bin/vite dev
ื•ืืฆืœื™ ืžื•ืคื™ืข ื”ืคืœื˜ ื”ื‘ื:
The CJS build of Vite's Node API is deprecated. See https://vitejs.dev/guide/troubleshooting.html#vite-cjs-node-api-deprecated for more details.

  VITE v5.2.13  ready in 242 ms

  โžœ  Local:   http://localhost:3036/vite-dev/
  โžœ  press h + enter to show help
^C
ืื ื™ ืขื•ืฆืจ ืื•ืชื• ืขื Ctrl+C ื›ื“ื™ ืœืชืงืŸ ื›ืžื” ืงื•ื ืคื™ื’ื•ืจืฆื™ื•ืช. ืžืจื™ืฆื™ื:
$ yarn add vite-plugin-rails typescript react react-dom @vitejs/plugin-react @types/react @types/react-dom
ื•ืื– ืžืฉื ื™ื ืืช ื”ืงื•ื‘ืฅ vite.config.ts ืœืชื•ื›ืŸ ื”ื‘ื:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import ViteRails from 'vite-plugin-rails'

export default defineConfig({
  plugins: [
    react(),
    ViteRails(),
  ],
})
ืžืžืฉื™ื›ื™ื ื‘ืฉื•ืจืช ื”ืคืงื•ื“ื” ื•ื™ื•ืฆืจื™ื ืืช ื”ืงื•ื ื˜ืจื•ืœืจ ื”ืจืืฉื•ืŸ:
$ ./bin/rails g controller HomeController index
ื•ืื– ื‘ืงื•ื‘ืฅ config/routes.rb ืื ื™ ืžื•ืกื™ืฃ ื”ืคื ื™ื” ืืœื™ื• ื›ื“ื™ ืฉื ื•ื›ืœ ืœืจืื•ืช ืื•ืชื• ื‘ื“ืคื“ืคืŸ:
Rails.application.routes.draw do
  root to: 'home#index'
end
ืžืคืขื™ืœื™ื ืืช ื”ืฉืจืช ืขื ./bin/rails s, ื ื›ื ืกื™ื ืœ localhost:3000 ื•ืจื•ืื™ื ืืช ื”ื“ืฃ ืฉื™ืฆืจื ื•. ืจื™ืืงื˜ ืงื•ื‘ืฅ ื” JavaScript ืฉื ื˜ืขืŸ ื›ืฉื”ื™ื™ืฉื•ื ืฉืœื ื• ืขื•ืœื” ื”ื•ื app/javascript/entrypoints/application.js. ืื ื™ ื™ื•ืฆืจ ืชื™ืงื™ื™ื” ื—ื“ืฉื” ื‘ืฉื app/frontend/components ื•ื‘ืชื•ื›ื” ืงื•ื‘ืฅ ื—ื“ืฉ ื‘ืฉื Home.tsx. ืชื•ื›ืŸ ื”ืงื•ื‘ืฅ ื”ื•ื:
import React from 'react';
import { createRoot } from 'react-dom/client';

function Home({text}: {
  text: string
}) {
  return <h1>{text}</h1>
}

const main = document.querySelector('main')!;
const root = createRoot(main);

root.render(<Home text="Hello World" />);
ื”ืงื•ื‘ืฅ ืžื’ื“ื™ืจ ืืช ื”ืงื•ืžืคื•ื ื ื˜ื” ื”ืจืืฉื•ื ื” ืฉืœื ื• ื•ื’ื ืžืจื ื“ืจ ืื•ืชื” ืœืžืกืš. ื–ื” ืขื“ื™ื™ืŸ ืœื ืžืกืคื™ืง ื˜ื•ื‘ ื›ื™ ื–ื” ืื•ืžืจ ืฉื›ืœ ืขืžื•ื“ ืฉื ื™ื›ื ืก ืืœื™ื• ื™ืฆื™ื’ ืืช ืื•ืชื” ืงื•ืžืคื•ื ื ื˜ื”. ืชื›ืฃ ื ืชืงืŸ ืืช ื–ื”. ืื‘ืœ ืงื•ื“ื ื‘ื•ืื• ื ืจืื” ืฉืจื•ืื™ื ืืช ื”ืงื•ืžืคื•ื ื ื˜ื” ืขืœ ื”ืžืกืš. ืœืคื ื™ ืฉื ื•ื›ืœ ืœื”ืชืงื“ื ื™ืฉ ืœืขื“ื›ืŸ ืืช ื”ืงื•ื‘ืฅ app/views/layouts/application.html ื›ืš ืฉื™ื•ื›ืœ ืœืจืขื ืŸ ื“ืคื™ vite ื•ื’ื ื™ื›ื™ืœ ืืœืžื ื˜ main ืืœื™ื• ื ืจื ื“ืจ ืืช ื”ืงื•ืžืคื•ื ื ื˜ื” ืฉื™ืฆืจื ื•. ืขื“ื›ื ื• ืืช ืชื•ื›ืŸ ื”ืงื•ื‘ืฅ ืœืงื•ื“ ื”ื‘ื:
<!DOCTYPE html>
<html>
  <head>
    <title>RailsReactTypescriptDemo</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">

    <% if Rails.env.development? %>
    <script type="module">
      import RefreshRuntime from 'http://localhost:3036/vite-dev/@react-refresh'
      RefreshRuntime.injectIntoGlobalHook(window)
      window.$RefreshReg$ = () => {}
      window.$RefreshSig$ = () => (type) => type
      window.__vite_plugin_react_preamble_installed__ = true
    </script>
    <% end %>

    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag "application" %>
    <%= vite_client_tag %>
    <%= vite_javascript_tag 'application' %>
    <!--
      If using a TypeScript entrypoint file:
        vite_typescript_tag 'application'

      If using a .jsx or .tsx entrypoint, add the extension:
        vite_javascript_tag 'application.jsx'

      Visit the guide for more information: https://vite-ruby.netlify.app/guide/rails
    -->

  </head>

  <body>
    <main />
    <%= yield %>

  </body>
</html>