Dari Sifar hingga Pelancaran: Pengambilan Utama daripada Perjalanan Pembangunan Dikuasakan Remix Kami

王林
Lepaskan: 2024-09-07 00:01:08
asal
449 orang telah melayarinya

Sekitar enam bulan yang lalu, saya membuat apa yang dikatakan oleh sesetengah orang sebagai keputusan berani dengan memilih Remix sebagai asas untuk aplikasi web syarikat kami. Cepat ke hari ini, dan saya rasa sudah tiba masanya untuk berundur dan merenung pilihan yang kami buat. Saya akan meneliti keputusan infrastruktur utama yang dibuat dan taburkan sedikit contoh penggunaan praktikal dalam perjalanan.

Jadi, tanpa berlengah lagi, mari kita beralih terus ke sorotan dan sorotan perjalanan ini — gabungan kepuasan dan pengajaran yang dipelajari.

From Zero to Launch: Key Takeaways from Our Remix-Powered Development Journey

Remix (atau patutkah saya katakan React Router?)

Sorotan: Remix

Ini mungkin keputusan infrastruktur "paling berisiko" yang saya buat pada masa itu, kerana Remix tidak begitu popular seperti NextJS dan tidak banyak contoh perusahaan besar menggunakan Remix untuk pengetahuan saya.
Cepat ke hari ini - ChatGPT berhijrah dari Next to Remix hanya beberapa hari yang lalu!

Seperti yang saya perincikan dalam artikel saya sebelum ini, saya memilih Remix atas banyak sebab, beberapa kerana kesederhanaannya, aspek "tindan penuh" (iaitu, menggunakan pelayan remix sebagai "belakang untuk bahagian hadapan") dan abstraksinya yang hebat untuk penghalaan, pengambilan data dan mutasi.

Nasib baik, Remix dihantar ? Rangka kerja ini intuitif, mudah dipelajari dan diajar orang lain serta memastikan amalan terbaik digunakan, menjadikan kedua-dua kod penulisan dan mengujinya dengan mudah.

Beberapa bulan selepas bekerja dengan Remix, mereka mengumumkan penggabungan rasmi dengan React Router, yang saya harap akan memujuk lebih ramai orang untuk menggunakannya, sama seperti langkah mereka ke vite lakukan.

Menjadi jelas kepada saya dalam banyak keadaan bahawa Remix adalah panggilan yang betul. Saya akan memberikan satu contoh praktikal yang saya tangani sejak kebelakangan ini - menggunakan satu contoh logger dalam pelayan remix untuk dapat melog dan mengesan tindakan dan ralat merentas keseluruhan apl untuk meningkatkan kebolehan pemantauan kami. Pelaksanaannya sangat lurus ke hadapan:

Langkah 1 - buat pembalak anda (dalam kes saya, saya menggunakan winston, yang berfungsi hebat dengan Datadog yang kami gunakan untuk pemantauan)

Langkah 2 - tambahkan pembalak anda pada konteks beban pelayan (dalam kes saya, ia adalah ekspres):

app.all(
  '*',
  createRequestHandler({
    getLoadContext: () => ({
      logger,
      // add any other context variables here
    }),
    mode: MODE,
    // ...
  }),
);
Salin selepas log masuk

Langkah 3 (untuk pengguna skrip taip) - kemas kini definisi jenis lalai Remix untuk memasukkan pembalak dalam konteks pemuatan apl

import '@remix-run/node';
import { type Logger } from 'winston';

declare module '@remix-run/node' {
  interface AppLoadContext {
    logger: Logger;
  }
}
Salin selepas log masuk

Langkah 4 - gunakan pembalak mengikut kehendak anda dalam mana-mana pemuat atau tindakan laluan!

export async function action({ request, context }: ActionFunctionArgs) {

  try {
    await someAction();
  } catch (e) {
    context.logger.error(e);
  }
}
Salin selepas log masuk

Sebelum kita menyimpulkan bahagian ini, saya ingin mengatakan bahawa terdapat juga perkara yang saya harap Remix ada tetapi masih belum, seperti pelaksanaan RSC untuk penstriman data/komponen, dan Route Middlewares yang sesuai untuk pengesahan /keizinan. Nasib baik, nampaknya perkara ini (dan ciri hebat yang lain) diutamakan dalam peta jalan mereka, jadi mudah-mudahan kami boleh mendapatkannya tidak lama lagi!

From Zero to Launch: Key Takeaways from Our Remix-Powered Development Journey

Pertanyaan Tanstack. Kegemaran sepanjang zaman

Sorotan: React Query

Memilih @tanstack/react-query merupakan keputusan yang mudah untuk saya, berdasarkan pengalaman positif saya yang lalu, dan kali ini juga tidak mengecewakan. API adalah serba boleh, boleh dipanjangkan dan tidak mempunyai pendapat dengan cara terbaik — menjadikannya mudah untuk disepadukan dengan alatan lain.

Saya sangat menyukainya sehingga saya memilihnya kerana mengetahui API dalaman kami berasaskan GraphQL, bukannya pilihan yang lebih jelas iaitu Apollo Client. Terdapat banyak sebab mengapa: Tanstack Query mempunyai API yang sangat baik, ia jauh lebih ringan daripada Apollo, dan kerana saya tidak mahu bergantung pada alat yang sangat disesuaikan dengan teknologi tertentu seperti GraphQL, sekiranya kita perlu menukar atau menggabungkan teknologi lain.

Selain itu, memandangkan kami menggunakan Remix, saya boleh menggunakan sepenuhnya keupayaan SSR Tanstack Query — pra-mengambil pertanyaan pada bahagian pelayan sambil mengekalkan keupayaan untuk mengubah, membatalkan atau mengambil semula pertanyaan ini pada bahagian klien. Berikut ialah contoh ringkas:

import { dehydrate, QueryClient, HydrationBoundary, useQuery } from '@tanstack/react-query';
import { json, useLoaderData } from '@remix-run/react';


const someDataQuery = {
  queryKey: ['some-data'],
  queryFn: () => fetchSomeData()
}

export async function loader() {
  const queryClient = new QueryClient();
  try {
    await queryClient.fetchQuery(someDataQuery);

    return json({ dehydrate: dehydrate(queryClient) });
  } catch (e) {
    // decide whether to handle the error or continue to
    // render the page and retry the query in the client
  }
}

export default function MyRouteComponent() {
  const { dehydratedState } = useLoaderData<typeof loader>();
  const { data } = useQuery(someDataQuery);

  return (
           <HydrationBoundary state={dehydratedState}>
             <SomeComponent data={data} />
           </HydrationBoundary />
  );
}
Salin selepas log masuk

From Zero to Launch: Key Takeaways from Our Remix-Powered Development Journey

Tailwind CSS

Highlight: Tailwind

I was initially skeptical about Tailwind, having never used it before, and because I didn’t quite understand the hype (it seemed to me at first just like syntactic sugar over CSS). However, I decided to give it a try because of its strong recommendations and popularity within the community, and I’m really glad I did. Tailwind’s utility-first approach made it incredibly easy to build a consistent and robust design system right from the start, which, looking back, was a total game changer.
It also pairs perfectly with shadcn, which we used, and together they allowed me to deliver quickly while keeping everything modular and easy to modify later on - a crucial advantage in a startup environment.

I also really like how easy it is to customize tailwind's theme to your needs - for example, overriding tailwind's default scheme:

First, define your colors as variable's under tailwind's main .css file:

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer base {

  :root {
    /* define the primitive design system tokens */
    --colors-blue-100: hsl(188 76% 90%);
    --colors-blue-200: hsl(187 63% 82%);
    --colors-blue-25: hsl(185 100% 98%);
    --colors-blue-300: hsl(190 52% 74%);
    --colors-blue-400: hsl(190 52% 61%);
    --colors-blue-50: hsl(188 92% 95%);
    --colors-blue-500: hsl(190 74% 39%);
    --colors-blue-600: hsl(191 77% 34%);
    --colors-blue-700: hsl(190 51% 35%);
    --colors-blue-800: hsl(191 52% 29%);
    --colors-blue-900: hsl(190 51% 23%);
    --colors-blue-950: hsl(190 52% 17%);
    --colors-gray-100: hsl(0 0 90%);
    --colors-gray-200: hsl(0 0 85%);
    --colors-gray-25: hsl(0 0 98%);
    --colors-gray-300: hsl(0 0 73%);
    --colors-gray-400: hsl(0 1% 62%);
    --colors-gray-50: hsl(0 0 94%);
    --colors-gray-500: hsl(0 0% 53%);
    --colors-gray-600: hsl(0 0 44%);
    --colors-gray-700: hsl(0 0 36%);
    --colors-gray-800: hsl(0 2% 28%);
    --colors-gray-900: hsl(0 0 20%);
    --colors-gray-950: hsl(0 0 5%);
    --colors-red-100: hsl(4 93% 94%);
    --colors-red-200: hsl(3 96% 89%);
    --colors-red-25: hsl(12 100% 99%);
    --colors-red-300: hsl(4 96% 80%);
    --colors-red-400: hsl(4 92% 69%);
    --colors-red-50: hsl(5 86% 97%);
    --colors-red-500: hsl(4 88% 61%);
    --colors-red-600: hsl(4 74% 49%);
    --colors-red-700: hsl(4 76% 40%);
    --colors-red-800: hsl(4 72% 33%);
    --colors-red-900: hsl(8 65% 29%);
    --colors-red-950: hsl(8 75% 19%);

    /*
      ...
    */

    /* define the semantic design system tokens */

    --primary-light: var(--colors-blue-200);
    --primary: var(--colors-blue-600);
    --primary-dark: var(--colors-blue-800);
    --primary-hover: var(--colors-blue-50);

    --text-default-primary: var(--colors-gray-700);
    --text-default-secondary: var(--colors-gray-800);
    --text-default-tertiary: var(--colors-gray-900);
    --text-default-disabled: var(--colors-gray-300);
    --text-default-read-only: var(--colors-gray-400);

    --disabled: var(--colors-gray-300);
    --tertiary: var(--colors-gray-50);

    /*
      ...
    */
  }
}
Salin selepas log masuk

Then, extend Tailwind's default theme via the tailwind config file:

import { type Config } from 'tailwindcss';

const ColorTokens = {
  BLUE: 'blue',
  GRAY: 'gray',
  RED: 'red',
} as const;

const generateColorScale = (colorName: string) => {
  const scales = [25, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
  return scales.reduce(
    (acc, scale) => {
      acc[scale] = `var(--colors-${colorName}-${scale})`;
      return acc;
    },
    {} as Record<string, string>,
  );
};

export const customColors = Object.values(ColorTokens).reduce((acc, color) => {
  return {
    ...acc,
    [color]: generateColorScale(color),
  };
}, {});

const config = {
  // ... additional config
  theme: {
    extend: {
      colors: customColors
    },
  },
} satisfies Config;

export default config;
Salin selepas log masuk

This is just the tip of the iceberg - you can go on to define custom spacing, text sizing and much more!

From Zero to Launch: Key Takeaways from Our Remix-Powered Development Journey

Playwright - makes writing e2e tests fun

Highlight: Playwright

Previously using Cypress, I was inclined to choose it, but I kept hearing hype around Playwright and figured I'll research it extensively before making a decision. After comparing Playwright with Cypress, it was clear Playwright is the right choice to make - the fact it comes with parallel execution out of the box, the broader browser support, running times and debugging capabilities - all made Playwright the obvious choice.
And, while this is very subjective, I like Playwright's syntax much better. I find it similar to React Testing Library's syntax, which I like, and I tend to think the tests are a lot more readable, with the asynchronous aspect of the tests being very straight forward, unlike the syntax of Cypress that can cause tests to feel bloated by .then() statements and subsequent indentations.

I think my favorite feature of Playwright is their implementation of Test Fixtures. They provide a clean way to initialize and reuse resources like page objects, making tests more modular and maintainable. Make sure to check out the above link to learn more about it!

From Zero to Launch: Key Takeaways from Our Remix-Powered Development Journey

Tanstack Table vs AG Grid

Lowlight: (Starting with) Tanstack Table

First off, let me clarify — @tanstack/react-table is a fantastic tool, which is why I was inclined to choose it in the first place, but it wasn’t the best fit for my particular use case. The very features that make it great, like its small bundle size and customizable API, ended up being less relevant to our needs than I originally thought. Despite having full control of the rendering of the Table, I was having some issues aligning its scrolling behavior to our desired outcome (why is it still not possible in 2024 to have a

element with dynamic sizing and scrolling on its body only, without resorting to clunky solutions? ?).

I soon realized that to deliver my feature fast and provide a good user experience, I needed a table with built-in features like pagination, column resizing and row auto-sizing, and I preferred having those out of the box over full control of the UI rendering. Additionally, since the table only appears after a query is run, I could lazy load it, making the bundle size less of a concern.

I highly recommend using the AG Grid theme builder to customize AG Grid according to your preferences/design system. And, for those using Cypress for their testing purposes - I found this cool plugin that abstracts AG Grid to easily interact with it in tests (sadly I could not find the same for Playwright ?)

Final thoughts

Looking back, I definitely feel a sense of pride in what we’ve accomplished. Not every decision was perfect, but taking the time to research and find the most fitting solution was worth it. And when things didn’t go as planned - it challenged us to think critically and adapt quickly, which is important no less.

Please let me know in the comments if there’s something you’d like to see explored further in future articles.
Here’s to more lessons learned, personal growth and having fun along the way ?

Atas ialah kandungan terperinci Dari Sifar hingga Pelancaran: Pengambilan Utama daripada Perjalanan Pembangunan Dikuasakan Remix Kami. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

sumber:dev.to
Kenyataan Laman Web ini
Kandungan artikel ini disumbangkan secara sukarela oleh netizen, dan hak cipta adalah milik pengarang asal. Laman web ini tidak memikul tanggungjawab undang-undang yang sepadan. Jika anda menemui sebarang kandungan yang disyaki plagiarisme atau pelanggaran, sila hubungi admin@php.cn
Tutorial Popular
Lagi>
Muat turun terkini
Lagi>
kesan web
Kod sumber laman web
Bahan laman web
Templat hujung hadapan