مقالات

چگونه وبلاگم را شروع کردم • جاش دبلیو کومو


در چند ماه گذشته من روی نسخه جدید این وبلاگ کار می کردم. چند هفته پیش سوئیچ را زدم! در اینجا یک موازی سریع وجود دارد:

صفحه اصلی وبلاگ (قدیمی)

نسخه قدیمی وبلاگ من، در حالت نور

صفحه اصلی وبلاگ (جدید)

نسخه جدید وبلاگ من در حالت تاریکنسخه جدید وبلاگ من در حالت نور

از نظر طراحی، خیلی تغییر نکرده است. من دوست دارم فکر کنم کمی ظریف تر است، اما ایده کلی همان است. بسیاری از جالب تغییرات در زیر کاپوت یا پنهان در جزئیات است. در این پست وبلاگ می خواهم به اشتراک بگذارم که پشته جدید چگونه است و به برخی از آن جزئیات بپردازم!

در طول سال ها، وبلاگ من به یک برنامه کاربردی پیچیده تبدیل شده است. تمام شد 100000 خط کد، بدون احتساب محتوا. مهاجرت به همه چیز پروژه بزرگی بود، اما فوق العاده آموزشی. من افکار صادقانه خود را در مورد تمام فناوری های جدیدی که برای این وبلاگ استفاده کرده ام به اشتراک خواهم گذاشت.

اگر می‌خواهید خودتان وبلاگی راه‌اندازی کنید یا از برخی از فناوری‌هایی که من استفاده می‌کنم استفاده می‌کنید، امیدواریم این پست بسیار مفید باشد!

بیایید با لیست کوتاهی از فناوری های اصلی استفاده شده توسط وبلاگ من شروع کنیم:

این فهرست احتمالاً برای یک وبلاگ بیش از حد به نظر می رسد، و چندین نفر از من پرسیده اند که چرا جایگزین “سبک تر” را انتخاب نکرده ام. چند دلیل وجود دارد:

  1. همه پست های وبلاگ من با استفاده از MDX نوشته شده اند، بنابراین من به پشتیبانی MDX ممتاز نیاز داشتم.

  2. پروژه اصلی دیگر من، پلتفرم دوره من، از Next.js استفاده می کند. من می‌خواستم تا آنجا که ممکن است اصطکاک تغییر متن کمتر باشد.

  3. من می‌خواستم با جدیدترین ویژگی‌های React، چیزهایی مانند مؤلفه‌های سرور و اقدامات، کمی تجربه بیشتر کسب کنم.

اگر به دلایل 2 و 3 نبود، احتمالاً داشتم Astro(در برگه جدید باز می شود) شلیک کرد. من هم کنجکاو بودم ریمیکس(در برگه جدید باز می شود) برای مدت طولانی! من فکر می کنم هر دو احتمالا گزینه های فوق العاده ای هستند.

من پست های وبلاگ را با استفاده از MDX می نویسم. این احتمالاً مهمترین بخش بسته فناوری برای من است.

اگر با MDX آشنایی ندارید، اساساً ترکیبی از Markdown و JSX است. می‌توانید آن را به‌عنوان یک ابرمجموعه از Markdown در نظر بگیرید که یک ابرقدرت اضافی را ارائه می‌کند: توانایی گنجاندن عناصر سفارشی React در محتوا.

با MDX، من می توانم ویجت های تعاملی ایجاد کنم و آنها را درست در وسط یک پست وبلاگ رها کنم، مانند این:

برگرفته از پست وبلاگ من، راهنمای تعاملی Flexbox.

این توانایی برای انواع محتوایی که من ایجاد می کنم بسیار مهم است. من نمی‌خواستم با مجموعه استاندارد عناصر Markdown (پیوندها، جداول، فهرست‌ها…) محدود شوم. با MDX می توانم من آیتم های خودم را ایجاد می کنم! این بسیار قدرتمندتر از Markdown سنتی یا محتوای متن غنی ذخیره شده در یک CMS است.

ممکن است از خود بپرسید: چرا به “full React” بروید و بخش Markdown را به طور کامل نادیده بگیرید؟ وقتی اولین نسخه این وبلاگ را در سال 2017 ایجاد کردم، این کار را انجام دادم. هر پست وبلاگ یک جزء React بود. این دو مشکل داشت:

  1. نوشته وحشتناکی بود شما باید هر پاراگراف را در یک بپیچید , for example, gets old really fast.
  2. There was no way to access the content as data. I couldn’t, for example, get a list of the 10 most recently updated blog posts, since each blog post was a chunk of code, not a database record or JSON object.

MDX solves both of these problems, and without really sacrificing anything. I still have the full power of React when I'm writing blog posts!

In terms of workflow, I edit my MDX files directly in VS Code and commit them as code. Article metadata (eg. title, publish date) is set in frontmatter at the top of the file. There are some drawbacks to this method (eg. I have to re-deploy the whole app to fix a typo), but I’ve found it’s the simplest option for me.

There are several ways to use MDX with Next.js. I'm using next-mdx-remote(opens in new tab), mostly because it’s what I use on my course platform and I want the two projects to be as similar as possible. If you’re building a brand-new blog using Next.js, it’s probably worth giving the built-in MDX support(opens in new tab) a shot; it seems a lot more straightforward.

The old version of my blog used styled-components, a CSS-in-JS library. As I’ve written about previously, styled-components isn’t fully compatible with React Server Components. So, for this new blog, I've switched to Linaria(opens in new tab), via the next-with-linaria integration(opens in new tab).

Here’s what it looks like:

import { styled } from '@linaria/react';

const Wrapper = styled.div`
  background: red;
`;

Linaria یک ابزار عالی است. آشنایی را پیشنهاد می کند styled API، اما به جای اینکه جادوی خود را در زمان اجرا انجام دهد، به جای آن در ماژول های CSS کامپایل می شود. این بدان معنی است که هیچ زمان اجرای JS در کار نیست و در نتیجه کاملاً با React Server Components سازگار است!

حالا کار کردن Linaria با Next یک نبرد سخت بود. من با چند مشکل عجیب برخورد کردم. به عنوان مثال، زمانی که من React را در یک فایل بدون در واقع وارد می کنم استفاده کنید این، من این خطای گیج کننده را دریافت می کنم:

EvalError: TextEncoder تعریف نشده است

/node_modules/.pnpm/@wyw-in-js+transform@0.4.1_typescript@5.4.5/node_modules/@wyw-in-js/transform/lib/module.js:223
پرتاب جدید EvalError(e.message, this.callstack.join('\n| '));

پیام‌های خطا/ردیابی پشته واقعاً کمکی نکردند، بنابراین بیشتر مشکلات را با بازگشت به تغییرات خود و/یا حذف موارد تصادفی تا زمانی که خطا برطرف شد، حل کردم. خوشبختانه، تمام مشکلاتی که پیدا کردم ثابت و قابل پیش بینی بود. این یکی از آن چیزهایی نیست که در آن اشتباه اتفاق می افتد گاهی اوقات، یا فقط در حال تولید است.

هنگامی که تمام ویژگی های خاص او را یاد گرفتم، همه چیز کاملاً روان بود، اگرچه یک مشکل اصلی باقی مانده است. و این به هیچ وجه به Linaria مربوط نمی شود، بلکه به نحوه مدیریت ماژول های CSS توسط Next.js مربوط می شود.

این یک حرکت بسیار بزرگ است که در این پست به درستی پوشش داده نمی شود، اما به طور خلاصه می توان گفت: Next.js "خوشبینانه" دسته ای از CSS را از مسیرهای نامرتبط ادغام می کند تا سرعت ناوبری بعدی را بهبود بخشد و ترتیب صحیح CSS را تضمین کند. برای مثال، این پست وبلاگ 245 کیلوبایت CSS را بارگیری می کند اما فقط از 47 کیلوبایت استفاده می کند.هر دو عدد مقادیر کامل فشرده نشده هستند. مقدار واقعی داده ارسال شده از طریق کابل کمتر است. یک بحث فعال در مورد وجود دارد Github(در برگه جدید باز می شود) در مورد این و به نظر می رسد برخی از گزینه های پیکربندی آینده ممکن است وضعیت را بهبود بخشد.

تمام آنچه گفته شد، من نمی توانم Linaria را توصیه کنم. این ابزار فوق‌العاده‌ای است، اما آنقدر آزمایش نشده است که بتواند راه‌حلی معقول برای اکثر افراد/تیم‌ها باشد.

من در حال حاضر بیشتر در مورد پیگمنت هیجان زده هستم CSS(در برگه جدید باز می شود)، یک ابزار CSS-in-JS با زمان صفر که توسط تیم سازنده Material UI توسعه یافته است. در آینده، این کتابخانه CSS خواهد بود که توسط کتابخانه مؤلفه MUI محبوب آنها استفاده می شود، به این معنی که به سرعت به یکی از آزمایش شده ترین کتابخانه های CSS تبدیل خواهد شد.

هنوز روزهای اولیه است، اما زمانی که آنها نسخه 1.0 را منتشر کردند، قصد دارم سعی کنم تغییر دهم. امیدواریم تا آن زمان، Next.js مشکل گروه بندی را با ماژول های CSS برطرف کرده باشد. 🤞

به لطف یک تم دستوری سفارشی، قطعات کد در وبلاگ جدید بسیار متفاوت به نظر می رسند! در اینجا قبل / بعد:

قطعه کد (قدیمی)

نسخه قدیمی قطعه کد من، در حالت تاریک

قطعه کد (جدید)

نسخه جدید کد من در حالت تاریک قرار می گیرد

اگر می خواهید از این تم در IDE خود استفاده کنید، می توانید فایل های JSON (تاریک، روشن) را دانلود کنید. من آن را تست نکرده ام، اما از همان دستور زبان VSCode و سایر ویرایشگرها استفاده می کند. باید کار کردن

پیوند به این عنوانجادوی استاتیک

من استفاده می کنم شیکی(در برگه جدید باز می شود) برای کنترل برجسته سازی نحو. اگرچه به طور خاص برای React ساخته نشده است، اما Shiki برای اجرا در زمان کامپایل طراحی شده است، و آن را برای اجزای سرور React مناسب می کند. به طرز شگفت انگیزی هیجان انگیز است.

در وبلاگ قدیمی خود، من از Prism، یک کتابخانه برجسته نحوی معمولی در سمت مشتری استفاده کردم. از آنجایی که تمام کدها در بسته جاوا اسکریپت گنجانده شده است، باید چند فداکاری انجام داد:

  • ما باید در مورد تعداد زبان هایی که پشتیبانی می کنیم بسیار محافظه کار باشیم، زیرا هر زبان اضافی کیلوبایت به بسته ما اضافه می کند.

  • منطق برجسته‌سازی نحو آسان‌تر است، بسیار ساده‌تر از برجسته‌سازی نحو در یک IDE مانند VS Code. این به سازندگان تم کنترل کمتری بر نتیجه نهایی می دهد و به این معنی است که نمی توانیم تم ها را بین IDE و Prism به اشتراک بگذاریم.

با حداقل مجموعه زبان‌های داخلی، Prism با ۲۶ کیلوبایت کوچک‌سازی می‌شود و gzipped(در برگه جدید باز می شود)، که برای یک برچسب نحوی فوق العاده کوچک است، اما همچنان یک افزودنی ضروری به بسته است.

با Shiki، 0 کیلوبایت به بسته جاوا اسکریپت اضافه می کند، از گرامر استاندارد TextMate مانند VS Code استفاده می کند و می تواند ده ها زبان را بدون هزینه اضافی پشتیبانی کند.

این به این معنی است که وقتی می‌خواهم یک قطعه Haskell را اضافه کنم، همانطور که در یک پست تصادفی وبلاگی که سال‌ها پیش نوشتم، آن را به طور کامل در نحو خط‌دار می‌شود:

pe58 = n
  where
  a p q = scanl (+) p $ iterate (+ 8) q
  b = [[x,y,z] | (x,(y,z))  zip (a 3 10) $ zip (a 5 12) (a 7 14)]
  c = zip (scanl1 (+) . map (length . filter isPrime) $ b) (iterate (+ 4) 5)
  [(n,_)] = take 1 $ dropWhile (\(_,(a,b)) -> 10*a > b) $ zip [3,5..] c

کار با Shiki به عنوان یک توسعه دهنده لذت بخش است. این فوق العاده انعطاف پذیر و قابل گسترش است. به عنوان مثال، من منطق "حاشیه" خود را ایجاد کردم تا بتوانم خطوط خاصی از کد را برجسته کنم:

function someRandomFunction() {
  // These two lines are highlighted! You can tell by the
  // background color, and the little bump on the left.

  return 42;
}

در وبلاگ قدیمی من، برجسته سازی نحو برای CSS-in-JS به درستی کار نمی کرد. رشته های قالب من به عنوان یک رشته استاندارد در نظر گرفته می شوند، نه کمی CSS تزریق شده در JS:

با Shiki، من می‌توانم از منطق برجسته‌سازی نحوی که VSCode روی کامپوننت‌های استایل‌گذاری شده استفاده می‌کنم. پسوند(در برگه جدید باز می شود) فراهم می کند. بنابراین، اجزای استایل من به درستی علامت گذاری شده اند:

const FunkyButton = styled.button`
  position: absolute;
  background: linear-gradient(
    to bottom,
    red,
    gold
  );

  @media (min-width: 24rem) {
    &:focus {
      background: gold;
    }
  }
`;

export default FunkyButton;

به همان اندازه که من شیکی را دوست دارم، برخی معاوضه ها وجود دارد.

از آنجایی که از مکانیزم برجسته‌سازی نحو قدرتمندتری استفاده می‌کند، به سرعت گزینه‌های دیگر نیست. من در ابتدا این پست‌های وبلاگ را «در صورت تقاضا» با استفاده از رندر سمت سرور استاندارد به‌جای تولید HTML استاتیک در زمان کامپایل ارائه کردم، اما متوجه شدم که Shiki سرعت کار را بسیار کند کرده است، مخصوصاً در صفحاتی که قطعات زیادی دارند. این مشکل را می توان با تغییر به تولید استاتیک یا با استفاده از حافظه پنهان HTTP حل کرد.

شیکی نیز حافظه گرسنه است. من با تمام شدن Node به مشکل برخوردم حافظه(در برگه جدید باز می شود)، و من مجبور شدم برای اینکه مطمئن شوم چندین نمونه از شیکی ایجاد نمی کنم، اصلاح کنم.

با این حال، بزرگترین مشکل این است که گاهی اوقات من نیاز به برجسته سازی نحوی دارم مشتری به عنوان مثال، در تولید کننده پالت سایه من، قطعه بر اساس نحوه ویرایش سایه ها توسط کاربر تغییر می کند:

هیچ راهی برای تولید این در زمان کامپایل وجود ندارد زیرا کد پویا است!

برای این موارد من یک دوما هایلایتر شیک. این یکی سبک تر است و تنها تعداد کمی از زبان ها را پشتیبانی می کند. و در بسته های پیش فرض من گنجانده نشده است، من آن را با تنبلی بارگذاری می کنم بعدی/پویا(در برگه جدید باز می شود). از آنجایی که خود برجسته سازی نحو کندتر است، من از useDeferredValue استفاده می کنم تا بقیه برنامه را سریع نگه دارم.

سخت ترین قسمت این بود که به آن نیاز داشتم هر دو یک جزء سرور استاتیک و همچنین یک مؤلفه مشتری پویا برای SSR که به درستی کار کند. پس از بارگیری همه چیز، مخفیانه بین آنها روی مشتری سوئیچ می کنم.

علاوه بر تکه‌های کد، زمین بازی کد، ویرایشگرهای کوچک به سبک Codepen نیز دارم:

کد زمین بازی

import React from 'react';
import range from 'lodash.range';

import styles from './PrideFlag.module.css';
import { COLORS } from './constants';

function PrideFlag({
  variant = 'rainbow', 
  width = 200,
  numOfColumns = 10,
  staggeredDelay = 100,
  billow = 2,
}) {
  const colors = COLORS[variant];

  const friendlyWidth =
    Math.round(width / numOfColumns) * numOfColumns;

  const firstColumnDelay = numOfColumns * staggeredDelay * -1;

  return (
    div className={styles.flag} style={{ width: friendlyWidth }}>
      {range(numOfColumns).map((index) => (
        div
          key={index}
          className={styles.column}
          style={{
            '--billow': index * billow + 'px',
            background: generateGradientString(colors),
            animationDelay:
              firstColumnDelay + index * staggeredDelay + 'ms',
          }}
        />
      ))}
    div>
  );
}

function generateGradientString(colors) {
  const numOfColors = colors.length;
  const segmentHeight = 100 / numOfColors;

  const gradientStops = colors.map((color, index) => {
    const from = index * segmentHeight;
    const to = (index + 1) * segmentHeight;

    return `${color} ${from}% ${to}%`;
  });

  return `linear-gradient(to bottom, ${gradientStops.join(', ')})`;
}

export default PrideFlag;

برگرفته از پست وبلاگ من، متحرک پرچم های غرور.

من برای زمین های بازی React استفاده می کنم بسته بندی شن و ماسه(در برگه جدید باز می شود)، یک ویرایشگر فوق العاده که توسط افراد CodeSandbox ایجاد شده است. من قبلاً در مورد نحوه استفاده از Sandpack نوشته ام و همه این موارد هنوز اعمال می شود.

برای HTML/CSS استاتیک از فورک خودم از agnym استفاده می کنم زمین بازی کودکان(در برگه جدید باز می شود). بسته بندی شن و ماسه انجام می دهد از قالب‌های استاتیک پشتیبانی می‌کنند، اما آن‌ها به Service Workers متکی هستند، که گاهی اوقات توسط تنظیمات حریم خصوصی مرورگر مسدود می‌شوند و در نتیجه یک تجربه کاربری خراب می‌شوند.

بسیاری از مردم از من پرسیده اند که چگونه می توانم دموهای تعاملی را در پست هایم مانند این ایجاد کنم:

مطمئنی

این عمل قابل لغو نیست.

برگرفته از پست وبلاگ من، طراحی سایه های زیبا در CSS.

من هرگز نمی دانم چگونه به این سوال پاسخ دهم 😅 من از کتابخانه ها یا بسته های خاصی برای این کار استفاده نمی کنم، همه چیز برای توسعه وب استاندارد است. من قابل استفاده مجدد خودم را ایجاد کردم مؤلفه‌ای که پوشش و مجموعه‌ای از کنترل‌ها را فراهم می‌کند، و من آن را برای هر ویجت جداگانه می‌نویسم.

با این حال، چند ابزار کلی وجود دارد که کمک می کند. من از React استفاده می کنم بهار(در برگه جدید باز می شود) برای درونیابی هموار بین مقادیر به روشی سیال و ارگانیک. من هم از Framer استفاده میکنم حرکت(در برگه جدید باز می شود) برای انیمیشن های چیدمان

داشتن دو کتابخانه انیمیشن مجزا بسیار لذت بخش است، به خصوص که هیچکدام کوچک نیستند ( 19.4 کیلوبایت(در برگه جدید باز می شود) و 44.6 کیلوبایت(در برگه جدید باز می شود)به ترتیب). من React Spring را به‌عنوان کتابخانه پایه اضافه می‌کنم و در صورت نیاز، Framer Motion را به صورت پویا وارد می‌کنم.

با این حال، راستش را بخواهید، Framer Motion باید بتواند هر کاری که React Spring می‌تواند انجام دهد را انجام دهد، بنابراین اگر مجبور باشم یک کتابخانه انیمیشن «جزیره صحرایی» انتخاب کنم، احتمالاً Framer Motion خواهد بود.

اگر در حال خواندن این مطلب در رایانه رومیزی هستید، ممکن است این پسر کوچک را در کنار خود دیده باشید:

این یک است مانند دکمه که به نوعی احمقانه است... شبکه های اجتماعی از دکمه هایی مانند این استفاده می کنند تا الگوریتم خود را در مورد اینکه کدام قسمت از محتوا ظاهر شود، استفاده می کنند. این وبلاگ هیچ الگوریتم اکتشافی ندارد، بنابراین هدفی جز زیبا بودن ندارد.

هر بازدید کننده می تواند تا 16 بار روی دکمه کلیک کند و داده ها در MongoDB ذخیره می شوند. ورودی پایگاه داده به شکل زیر است:

{
  "slug": "promises",
  "categorySlug": "javascript",
  "hits": 123456,
  "likesByUser": {
    "abc123": 16,
    "def456": 4,
    "ghi789": 16,
    // ...
  }
}

شناسه ها بر اساس آدرس IP کاربر هش شده با استفاده از نمک مخفی برای حفظ ناشناس بودن تولید می شوند. این وبلاگ در Vercel مستقر شده است و Vercel IP را از طریق یک هدر در اختیار کاربر قرار می دهد.

در ابتدا از شناسه‌هایی استفاده می‌کردم که روی کلاینت تولید شده و در محلی ذخیره می‌شدند، اما کاراگاه افسانه‌ای جین منچون وانگ با ارسال هرزنامه به نقطه پایانی API و ایجاد ده‌ها هزار لایک به من نشان داد که چرا این ایده بدی است. 😅

یکی از چیزهای مورد علاقه من در مورد Next.js این است که شما به Node.js باطن جداگانه نیاز ندارید. منطق لایک کردن پست ها در Route انجام می شود دستکاری کننده(در برگه جدید باز می شود)، که تقریباً دقیقاً مانند یک نقطه پایانی Express عمل می کند.

پیوند به این عنوانانسجام عنصر

من زمان غیر منطقی را صرف کردم متنی سبک، مطمئن شوید که اجزای مشترک "آجرهای LEGO" من به خوبی با هم ترکیب شده اند.

مثلا من دارم


Source link

نوشته های مشابه

دیدگاهتان را بنویسید

همچنین ببینید
بستن
دکمه بازگشت به بالا