Rumah >hujung hadapan web >tutorial js >Dari Next.js untuk React Edge dengan Cloudflare Workers: A Liberation Story

Dari Next.js untuk React Edge dengan Cloudflare Workers: A Liberation Story

DDD
DDDasal
2024-11-20 13:58:12937semak imbas
  • Sedotan Terakhir
  • Alternatif dengan Cloudflare?
  • React Edge: Rangka Kerja React yang diperoleh daripada semua (atau hampir) kesakitan pembangun
    • Keajaiban RPC Ditaip
    • Kuasa penggunaanFetch: Di Mana Keajaiban Berlaku
  • Beyond useFetch: Senjata lengkap
    • RPC: Seni Komunikasi Pelanggan-Pelayan
    • Sistem i18n yang Masuk akal
    • Pengesahan JWT yang "Just Works"
    • Kedai Kongsi
    • Penghalaan Elegan
    • Cache Teragih dengan Cache Tepi
  • Pautan: Komponen Berfikiran Hadapan
  • app.useContext: Gerbang ke Edge
  • app.useUrlState: Status Disegerakkan dengan URL
  • app.useStorageState: Keadaan Berterusan
  • app.useDebounce: Kawalan Frekuensi
  • app.useDistinct: Status tanpa Pendua
  • The React Edge CLI: Kuasa di Hujung Jari Anda
  • Kesimpulan

Titisan Terakhir

Semuanya bermula dengan invois daripada Vercel. Tidak, ia sebenarnya bermula lebih awal - dengan kekecewaan kecil yang timbul. Keperluan untuk membayar ciri asas seperti perlindungan DDoS, log yang lebih terperinci, atau juga tembok api yang baik, membina baris gilir, dsb. Rasa terperangkap dalam lock-in vendor yang semakin mahal.

"Dan yang paling teruk: pengepala SEO berharga kami hanya berhenti dipaparkan pada pelayan dalam aplikasi menggunakan penghala halaman. Sakit kepala sebenar bagi mana-mana pembangun! ?"

Tetapi apa yang benar-benar membuatkan saya memikirkan semula segala-galanya ialah arah yang diambil oleh Next.js. Pengenalan pelanggan penggunaan, pelayan penggunaan - arahan yang dalam teori harus memudahkan pembangunan, tetapi dalam amalan menambah satu lagi lapisan kerumitan untuk diurus. Seolah-olah kami akan kembali ke zaman PHP, menandai fail dengan arahan untuk memberitahu mereka di mana ia harus dijalankan.

Dan ia tidak berhenti di situ. App Router, idea yang menarik, tetapi dilaksanakan dengan cara yang mencipta rangka kerja yang boleh dikatakan baharu dalam Next.js. Tiba-tiba kami mempunyai dua cara yang berbeza untuk melakukan perkara yang sama. Yang 'lama' dan 'baru' - dengan gelagat yang berbeza secara halus dan perangkap tersembunyi.

Alternatif dengan Cloudflare?

Ketika itulah saya menyedari: mengapa tidak mengambil kesempatan daripada infrastruktur Cloudflare yang luar biasa dengan Pekerja berjalan di tepi, R2 untuk storan, KV untuk data yang diedarkan... Selain itu, sudah tentu, perlindungan DDoS yang luar biasa, CDN global, firewall, peraturan untuk halaman dan laluan dan segala-galanya yang ditawarkan oleh Cloudflare.

Dan yang terbaik: model harga yang berpatutan, di mana anda membayar untuk apa yang anda gunakan, tanpa kejutan.

Beginilah cara React Edge dilahirkan. Rangka kerja yang tidak cuba mencipta semula roda, sebaliknya memberikan pengalaman pembangunan yang benar-benar mudah dan moden.

React Edge: Rangka Kerja React yang diperoleh daripada semua (atau hampir) kesakitan pembangun

Apabila saya mula membangunkan React Edge, saya mempunyai matlamat yang jelas: untuk mencipta rangka kerja yang masuk akal. Tiada lagi bergelut dengan arahan yang mengelirukan, tiada lagi bayaran untuk ciri asas, dan yang paling penting, tiada lagi perlu berurusan dengan kerumitan buatan yang dicipta oleh pemisahan klien/pelayan. Saya mahukan kelajuan, sesuatu yang memberikan prestasi tanpa mengorbankan kesederhanaan. Dengan memanfaatkan pengetahuan saya tentang API React dan bertahun-tahun sebagai pembangun Javascript dan Golang, saya tahu dengan tepat cara mengendalikan strim dan pemultipleksan untuk mengoptimumkan pemaparan dan pengurusan data.

Cloudflare Workers, dengan infrastruktur yang berkuasa dan kehadiran globalnya, menawarkan saya persekitaran yang sempurna untuk meneroka kemungkinan ini. Saya mahukan sesuatu yang benar-benar hibrid, dan gabungan alatan serta pengalaman inilah yang memberi kehidupan kepada React Edge: rangka kerja yang menyelesaikan masalah sebenar dengan penyelesaian moden dan cekap.

React Edge membawa pendekatan revolusioner kepada pembangunan React. Bayangkan anda boleh menulis kelas pada pelayan dan memanggilnya terus daripada klien, dengan menaip penuh dan konfigurasi sifar. Bayangkan sistem caching teragih yang "hanya berfungsi", membenarkan penolakan oleh teg atau awalan. Bayangkan anda boleh berkongsi keadaan antara pelayan dan pelanggan dengan cara yang telus dan selamat. Selain memudahkan pengesahan dan membawa pendekatan pengantarabangsaan yang cekap, CLI dan banyak lagi.

Komunikasi RPC anda sangat semula jadi seolah-olah seperti sihir - anda menulis kaedah dalam kelas dan memanggilnya daripada pelanggan seolah-olah kaedah itu tempatan. Sistem pemultipleksan pintar memastikan bahawa, walaupun berbilang komponen membuat panggilan yang sama, hanya satu permintaan dibuat kepada pelayan. Cache ephemeral mengelakkan permintaan berulang yang tidak perlu, dan semua ini berfungsi pada kedua-dua pelayan dan pelanggan.

Salah satu perkara yang paling berkesan ialah app.useFetch hook, yang menyatukan pengalaman pengambilan data. Pada pelayan, ia pramuat data semasa SSR; pada pelanggan, ia menghidrat secara automatik dengan data ini dan membenarkan kemas kini atas permintaan. Dan dengan sokongan untuk tinjauan automatik dan kereaktifan berasaskan pergantungan, mencipta antara muka dinamik tidak pernah semudah ini.

Tetapi ia tidak berhenti di situ. Rangka kerja ini menawarkan sistem penghalaan yang berkuasa (diilhamkan oleh Hono yang hebat), pengurusan aset yang disepadukan dengan Cloudflare R2, dan cara yang elegan untuk menangani ralat melalui kelas HttpError. Middleware boleh menghantar data kepada pelanggan dengan mudah melalui kedai kongsi dan semuanya dikaburkan secara automatik untuk keselamatan.

Yang paling mengagumkan? Hampir semua kod rangka kerja adalah hibrid. Tiada versi 'klien' dan 'pelayan' - kod yang sama berfungsi dalam kedua-dua persekitaran, secara automatik menyesuaikan diri dengan konteks. Pelanggan hanya menerima apa yang mereka perlukan, menjadikan himpunan terakhir sangat dioptimumkan.

Dan icing pada kek: semua ini berjalan pada infrastruktur tepi Cloudflare Workers, memberikan prestasi luar biasa pada kos yang berpatutan. Tiada kejutan pada rang undang-undang, tiada ciri asas yang tersembunyi di sebalik rancangan perusahaan paksa, hanya rangka kerja yang kukuh yang membolehkan anda memberi tumpuan kepada perkara yang benar-benar penting: mencipta aplikasi yang luar biasa. Selain itu, React Edge memanfaatkan keseluruhan ekosistem Cloudflare, termasuk Baris Gilir, Objek Tahan Lama, Storan KV dan banyak lagi untuk menyediakan asas yang teguh dan berskala untuk aplikasi anda.

Vite digunakan sebagai asas, baik untuk persekitaran pembangunan dan untuk ujian dan binaan. Vite, dengan kelajuan yang mengagumkan dan seni bina moden, membolehkan aliran kerja yang tangkas dan cekap. Ia bukan sahaja mempercepatkan pembangunan, tetapi juga mengoptimumkan proses binaan, memastikan kod disusun dengan cepat dan tepat. Tidak syak lagi, Vite ialah pilihan yang tepat untuk React Edge.

Memikirkan Semula Pembangunan Reaksi untuk Era Pengkomputeran Edge

Pernahkah anda terfikir bagaimana rasanya membangunkan aplikasi React tanpa perlu risau tentang halangan pelanggan/pelayan? Tanpa perlu menghafal berpuluh-puluh arahan seperti menggunakan klien atau menggunakan pelayan? Dan lebih baik lagi: bagaimana jika anda boleh memanggil fungsi pelayan seolah-olah ia adalah tempatan, dengan penaipan penuh dan konfigurasi sifar?

Dengan React Edge, anda tidak perlu:

  • Buat laluan API berasingan
  • Urus status pemuatan/ralat secara manual
  • Laksanakan nyahlantun dengan tangan
  • Bimbang tentang pensirilan/deserialisasi
  • Kendalikan CORS
  • Urus menaip antara klien/pelayan
  • Kendalikan peraturan pengesahan secara manual
  • Urus cara pengantarabangsaan dilakukan

Dan bahagian yang terbaik: semua ini berfungsi pada kedua-dua pelayan dan pelanggan, tanpa perlu menandakan apa-apa dengan menggunakan klien atau menggunakan pelayan. Rangka kerja tahu apa yang perlu dilakukan berdasarkan konteks. Boleh kita pergi?

Keajaiban RPC Ditaip

Bayangkan boleh melakukan ini:

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};

Bandingkan ini dengan Next.js/Vercel:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}

Kuasa penggunaanFetch: Di Mana Sihir Berlaku

Pengambilan Data Difikirkan Semula

Lupakan semua yang anda ketahui tentang pengambilan data dalam React. App.useFetch React Edge membawa pendekatan yang benar-benar baharu dan berkuasa. Bayangkan cangkuk yang:

  • Pramuat data ke pelayan semasa SSR
  • Melembabkan pelanggan secara automatik tanpa kelipan
  • Mengekalkan penaipan lengkap antara klien dan pelayan
  • Menyokong kereaktifan dengan nyahlantun pintar
  • Memultipleks panggilan yang serupa secara automatik
  • Membenarkan kemas kini program dan tinjauan pendapat

Mari kita lihat tindakan ini:

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};

Keajaiban Multiplexing

Contoh di atas menyembunyikan ciri berkuasa: pemultipleksan pintar. Apabila anda menggunakan ctx.rpc.batch, React Edge bukan sahaja membatch panggilan - ia secara automatik menyahduplikasi panggilan yang sama:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}

Penghidratan Sempurna SSR

Salah satu bahagian yang paling mengagumkan ialah cara useFetch mengendalikan SSR:

// Primeiro, definimos nossa API no servidor
class PropertiesAPI extends Rpc {
 async searchProperties(filters: PropertyFilters) {
   const results = await this.db.properties.search(filters);
   // Cache automático por 5 minutos
   return this.createResponse(results, {
     cache: { ttl: 300, tags: ['properties'] }
   });
 }

 async getPropertyDetails(ids: string[]) {
   return Promise.all(
     ids.map(id => this.db.properties.findById(id))
   );
 }
}

// Agora, no cliente, a mágica acontece
const PropertySearch = () => {
 const [filters, setFilters] = useState<PropertyFilters>({
   price: { min: 100000, max: 500000 },
   bedrooms: 2
 });

 // Busca reativa com debounce inteligente
 const { 
   data: searchResults,
   loading: searchLoading,
   error: searchError
 } = app.useFetch(
   async (ctx) => ctx.rpc.searchProperties(filters),
   {
     // Quando filters muda, refaz a busca
     deps: [filters],
     // Mas espera 300ms de 'silêncio' antes de buscar
     depsDebounce: {
       filters: 300
     }
   }
 );

 // Agora, vamos buscar os detalhes das propriedades encontradas
 const {
   data: propertyDetails,
   loading: detailsLoading,
   fetch: refreshDetails
 } = app.useFetch(
   async (ctx) => {
     if (!searchResults?.length) return null;

     // Isso parece fazer múltiplas chamadas, mas...
     return ctx.rpc.batch([
       // Na verdade, tudo é multiplexado em uma única requisição!
       ...searchResults.map(result => 
         ctx.rpc.getPropertyDetails(result.id)
       )
     ]);
   },
   {
     // Atualiza sempre que searchResults mudar
     deps: [searchResults]
   }
 );

 // Interface bonita e responsiva
 return (
   <div>
     <FiltersPanel 
       value={filters}
       onChange={setFilters}
       disabled={searchLoading}
     />

     {searchError && (
       <Alert status='error'>
         Erro na busca: {searchError.message}
       </Alert>
     )}

     <PropertyGrid
       items={propertyDetails || []}
       loading={detailsLoading}
       onRefresh={() => refreshDetails()}
     />
   </div>
 );
};

Beyond useFetch: Senjata lengkap

RPC: Seni Komunikasi Pelanggan-Pelayan

Keselamatan dan Enkapsulasi

Sistem RPC React Edge telah direka bentuk dengan mengambil kira keselamatan dan enkapsulasi. Tidak semua dalam kelas RPC didedahkan secara automatik kepada pelanggan:

const PropertyListingPage = () => {
  const { data } = app.useFetch(async (ctx) => {
    // Mesmo que você faça 100 chamadas idênticas...
    return ctx.rpc.batch([
      ctx.rpc.getProperty('123'),
      ctx.rpc.getProperty('123'), // mesma chamada
      ctx.rpc.getProperty('456'),
      ctx.rpc.getProperty('456'), // mesma chamada
    ]);
  });

  // Mas na realidade:
  // 1. O batch agrupa todas as chamadas em UMA única requisição HTTP
  // 2. Chamadas idênticas são deduplicas automaticamente
  // 3. O resultado é distribuído corretamente para cada posição do array
  // 4. A tipagem é mantida para cada resultado individual!


  // Entao..
  // 1. getProperty('123')
  // 2. getProperty('456')
  // E os resultados são distribuídos para todos os chamadores!
};

Hierarki API RPC

Salah satu ciri RPC yang paling berkuasa ialah keupayaan untuk menyusun API ke dalam hierarki:

const ProductPage = ({ productId }: Props) => {
  const { data, loaded, loading, error } = app.useFetch(
    async (ctx) => ctx.rpc.getProduct(productId),
    {
      // Controle fino de quando executar
      shouldFetch: ({ worker, loaded }) => {
        // No worker (SSR): sempre busca
        if (worker) return true;
        // No cliente: só busca se não tiver dados
        return !loaded;
      }
    }
  );

  // No servidor:
  // 1. useFetch faz a chamada RPC
  // 2. Dados são serializados e enviados ao cliente
  // 3. Componente renderiza com os dados

  // No cliente:
  // 1. Componente hidrata com os dados do servidor
  // 2. Não faz nova chamada (shouldFetch retorna false)
  // 3. Se necessário, pode refazer a chamada com data.fetch()

  return (
    <Suspense fallback={<ProductSkeleton />}>
      <ProductView 
        product={data}
        loading={loading}
        error={error}
      />
    </Suspense>
  );
};

Faedah Hierarki

Mengatur API ke dalam hierarki membawa beberapa faedah:

  • Organisasi Logik: Kumpulan fungsi berkaitan dengan cara yang intuitif
  • Ruang Nama Asli: Elakkan konflik nama dengan laluan yang jelas (users.preferences.getTheme)
  • Encapsulation: Pastikan kaedah pembantu peribadi pada setiap peringkat
  • Kebolehselenggaraan: Setiap subkelas boleh dikekalkan dan diuji secara bebas
  • Taip Lengkap: TypeScript memahami keseluruhan hierarki

Sistem RPC React Edge menjadikan komunikasi pelanggan-pelayan begitu semula jadi sehingga anda hampir terlupa bahawa anda sedang membuat panggilan jauh. Dan dengan keupayaan untuk menyusun API ke dalam hierarki, anda boleh mencipta struktur yang kompleks sambil memastikan kod anda teratur dan selamat.

Sistem i18n yang Masuk akal

React Edge membawakan sistem pengantarabangsaan yang elegan dan fleksibel yang menyokong interpolasi pembolehubah dan pemformatan kompleks tanpa perpustakaan yang berat.

class PaymentsAPI extends Rpc {
 // Propriedades nunca são expostas
 private stripe = new Stripe(process.env.STRIPE_KEY);

 // Métodos começando com $ são privados
 private async $validateCard(card: CardInfo) {
   return await this.stripe.cards.validate(card);
 }

 // Métodos começando com _ também são privados
 private async _processPayment(amount: number) {
   return await this.stripe.charges.create({ amount });
 }

 // Este método é público e acessível via RPC
 async createPayment(orderData: OrderData) {
   // Validação interna usando método privado
   const validCard = await this.$validateCard(orderData.card);
   if (!validCard) {
     throw new HttpError(400, 'Invalid card');
   }

   // Processamento usando outro método privado
   const payment = await this._processPayment(orderData.amount);
   return payment;
 }
}

// No cliente:
const PaymentForm = () => {
 const { rpc } = app.useContext<App.Context>();

 // ✅ Isso funciona
 const handleSubmit = () => rpc.createPayment(data);

 // ❌ Isso não é possível - métodos privados não são expostos
 const invalid1 = () => rpc.$validateCard(data);
 const invalid2 = () => rpc._processPayment(100);

 // ❌ Isso também não funciona - propriedades não são expostas
 const invalid3 = () => rpc.stripe;
};

Penggunaan dalam kod:

// APIs aninhadas para melhor organização
class UsersAPI extends Rpc {
  // Subclasse para gerenciar preferences
  preferences = new UserPreferencesAPI();
  // Subclasse para gerenciar notificações
  notifications = new UserNotificationsAPI();

  async getProfile(id: string) {
    return this.db.users.findById(id);
  }
}

class UserPreferencesAPI extends Rpc {
  async getTheme(userId: string) {
    return this.db.preferences.getTheme(userId);
  }

  async setTheme(userId: string, theme: Theme) {
    return this.db.preferences.setTheme(userId, theme);
  }
}

class UserNotificationsAPI extends Rpc {
  // Métodos privados continuam privados
  private async $sendPush(userId: string, message: string) {
    await this.pushService.send(userId, message);
  }

  async getSettings(userId: string) {
    return this.db.notifications.getSettings(userId);
  }

  async notify(userId: string, notification: Notification) {
    const settings = await this.getSettings(userId);
    if (settings.pushEnabled) {
      await this.$sendPush(userId, notification.message);
    }
  }
}

// No cliente:
const UserProfile = () => {
  const { rpc } = app.useContext<App.Context>();

  const { data: profile } = app.useFetch(
    async (ctx) => {
      // Chamadas aninhadas são totalmente tipadas
      const [user, theme, notificationSettings] = await ctx.rpc.batch([
        // Método da classe principal
        ctx.rpc.getProfile('123'),
        // Método da subclasse de preferências
        ctx.rpc.preferences.getTheme('123'),
        // Método da subclasse de notificações
        ctx.rpc.notifications.getSettings('123')
      ]);

      return { user, theme, notificationSettings };
    }
  );

  // ❌ Métodos privados continuam inacessíveis
  const invalid = () => rpc.notifications.$sendPush('123', 'hello');
};

Konfigurasi Sifar

React Edge mengesan dan memuatkan terjemahan anda secara automatik dan boleh menyimpan pilihan pengguna dengan mudah dalam kuki. Tetapi anda sudah menjangkakannya, bukan?

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};

Pengesahan JWT yang "Hanya Berfungsi"

Pengesahan sentiasa menjadi masalah dalam aplikasi web. Menguruskan token JWT, kuki selamat, pengesahan semula - semua ini biasanya memerlukan banyak kod boilerplate. React Edge mengubah ini sepenuhnya.

Lihat betapa mudahnya untuk melaksanakan sistem pengesahan lengkap:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}

Penggunaan Pelanggan: Konfigurasi Sifar

// Primeiro, definimos nossa API no servidor
class PropertiesAPI extends Rpc {
 async searchProperties(filters: PropertyFilters) {
   const results = await this.db.properties.search(filters);
   // Cache automático por 5 minutos
   return this.createResponse(results, {
     cache: { ttl: 300, tags: ['properties'] }
   });
 }

 async getPropertyDetails(ids: string[]) {
   return Promise.all(
     ids.map(id => this.db.properties.findById(id))
   );
 }
}

// Agora, no cliente, a mágica acontece
const PropertySearch = () => {
 const [filters, setFilters] = useState<PropertyFilters>({
   price: { min: 100000, max: 500000 },
   bedrooms: 2
 });

 // Busca reativa com debounce inteligente
 const { 
   data: searchResults,
   loading: searchLoading,
   error: searchError
 } = app.useFetch(
   async (ctx) => ctx.rpc.searchProperties(filters),
   {
     // Quando filters muda, refaz a busca
     deps: [filters],
     // Mas espera 300ms de 'silêncio' antes de buscar
     depsDebounce: {
       filters: 300
     }
   }
 );

 // Agora, vamos buscar os detalhes das propriedades encontradas
 const {
   data: propertyDetails,
   loading: detailsLoading,
   fetch: refreshDetails
 } = app.useFetch(
   async (ctx) => {
     if (!searchResults?.length) return null;

     // Isso parece fazer múltiplas chamadas, mas...
     return ctx.rpc.batch([
       // Na verdade, tudo é multiplexado em uma única requisição!
       ...searchResults.map(result => 
         ctx.rpc.getPropertyDetails(result.id)
       )
     ]);
   },
   {
     // Atualiza sempre que searchResults mudar
     deps: [searchResults]
   }
 );

 // Interface bonita e responsiva
 return (
   <div>
     <FiltersPanel 
       value={filters}
       onChange={setFilters}
       disabled={searchLoading}
     />

     {searchError && (
       <Alert status='error'>
         Erro na busca: {searchError.message}
       </Alert>
     )}

     <PropertyGrid
       items={propertyDetails || []}
       loading={detailsLoading}
       onRefresh={() => refreshDetails()}
     />
   </div>
 );
};

Mengapa ini revolusioner?

  1. Sifar Plat Dandang

    • Tiada pengurusan kuki manual
    • Tidak perlu pemintas
    • Tiada manual token naik taraf
  2. Keselamatan secara Lalai

    • Token disulitkan secara automatik
    • Kuki adalah selamat dan httpSahaja
    • Pengesahan semula automatik
  3. Taip Lengkap

    • Muatan JWT dimasukkan
    • Pengesahan dengan Zod bersepadu
    • Ralat pengesahan ditaip
  4. Penyatuan Lancar

const PropertyListingPage = () => {
  const { data } = app.useFetch(async (ctx) => {
    // Mesmo que você faça 100 chamadas idênticas...
    return ctx.rpc.batch([
      ctx.rpc.getProperty('123'),
      ctx.rpc.getProperty('123'), // mesma chamada
      ctx.rpc.getProperty('456'),
      ctx.rpc.getProperty('456'), // mesma chamada
    ]);
  });

  // Mas na realidade:
  // 1. O batch agrupa todas as chamadas em UMA única requisição HTTP
  // 2. Chamadas idênticas são deduplicas automaticamente
  // 3. O resultado é distribuído corretamente para cada posição do array
  // 4. A tipagem é mantida para cada resultado individual!


  // Entao..
  // 1. getProperty('123')
  // 2. getProperty('456')
  // E os resultados são distribuídos para todos os chamadores!
};

Kedai Kongsi

Salah satu ciri React Edge yang paling berkuasa ialah keupayaannya untuk berkongsi keadaan dengan selamat antara pekerja dan pelanggan. Mari lihat cara ini berfungsi:

const ProductPage = ({ productId }: Props) => {
  const { data, loaded, loading, error } = app.useFetch(
    async (ctx) => ctx.rpc.getProduct(productId),
    {
      // Controle fino de quando executar
      shouldFetch: ({ worker, loaded }) => {
        // No worker (SSR): sempre busca
        if (worker) return true;
        // No cliente: só busca se não tiver dados
        return !loaded;
      }
    }
  );

  // No servidor:
  // 1. useFetch faz a chamada RPC
  // 2. Dados são serializados e enviados ao cliente
  // 3. Componente renderiza com os dados

  // No cliente:
  // 1. Componente hidrata com os dados do servidor
  // 2. Não faz nova chamada (shouldFetch retorna false)
  // 3. Se necessário, pode refazer a chamada com data.fetch()

  return (
    <Suspense fallback={<ProductSkeleton />}>
      <ProductView 
        product={data}
        loading={loading}
        error={error}
      />
    </Suspense>
  );
};

Bagaimana Ia Berfungsi

  • Data Awam: Data yang ditandakan sebagai awam dikongsi dengan selamat dengan pelanggan, menjadikannya mudah diakses oleh komponen.
  • Data Peribadi: Data sensitif kekal dalam persekitaran pekerja dan tidak pernah terdedah kepada pelanggan.
  • Penyepaduan Perisian Tengah: Perisian Tengah boleh mengisi gedung dengan data awam dan peribadi, memastikan aliran maklumat berterusan antara logik pelayan dan pemaparan sebelah pelanggan.

Faedah

  1. Keselamatan: Pengasingan skop data awam dan peribadi memastikan maklumat sulit kekal dilindungi.
  2. Kemudahan: Akses telus untuk menyimpan data memudahkan pengurusan keadaan antara pekerja dan pelanggan.
  3. Fleksibiliti: Kedai mudah disepadukan dengan perisian tengah, membenarkan kemas kini status dinamik berdasarkan pengendalian permintaan.

Penghalaan Elegan

Sistem penghalaan React Edge diilhamkan oleh Hono, tetapi dengan kuasa besar untuk SSR:

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};

Ciri-ciri Utama

  • Laluan Berkumpulan: Pengumpulan logik laluan berkaitan di bawah laluan kongsi dan perisian tengah. Pengendali Fleksibel: Tentukan pengendali yang mengembalikan halaman atau respons API langsung.
  • Pengepala Per-Laluan: Sesuaikan pengepala HTTP untuk laluan individu.
  • Cache Bersepadu: Permudahkan strategi caching dengan ttl dan teg.

Faedah

  1. Ketekalan: Dengan mengumpulkan laluan berkaitan bersama, anda memastikan aplikasi perisian tengah dan organisasi kod yang konsisten.
  2. Kebolehskalaan: Sistem ini menyokong penghalaan bersarang dan modular untuk aplikasi berskala besar.
  3. Prestasi: Sokongan cache asli memastikan masa tindak balas yang optimum tanpa konfigurasi manual.

Cache Teragih dengan Cache Tepi

React Edge mempunyai sistem caching yang berkuasa yang berfungsi untuk kedua-dua data JSON dan keseluruhan halaman:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}

Ciri-ciri Utama

  • Pembatalan Berasaskan Tag: Entri cache boleh dikumpulkan menggunakan teg, membolehkan ketidaksahihan yang mudah dan terpilih apabila data berubah.
  • Padanan Awalan: Batalkan berbilang entri cache menggunakan awalan biasa, sesuai untuk senario seperti pertanyaan carian atau data hierarki.
  • Masa untuk Hidup (TTL): Tetapkan masa tamat tempoh untuk entri cache bagi memastikan data baharu sambil mengekalkan prestasi tinggi.

Faedah

  1. Prestasi yang Dipertingkat: Mengurangkan beban pada API dengan menyediakan respons cache untuk data yang kerap diakses.
  2. Kebolehskalaan: Mengurus set data yang besar dan trafik tinggi dengan cekap dengan sistem caching teragih.
  3. Fleksibiliti: Kawalan terperinci ke atas caching, membolehkan pembangun mengoptimumkan prestasi tanpa mengorbankan ketepatan data.

Pautan: Komponen Berfikiran Hadapan

Komponen Pautan ialah penyelesaian pintar dan berprestasi untuk pramuat sumber di sisi pelanggan, memastikan navigasi yang lebih lancar dan lebih pantas untuk pengguna. Fungsi prefetching diaktifkan apabila menuding kursor pada pautan, mengambil kesempatan daripada saat pengguna tidak aktif untuk meminta data destinasi terlebih dahulu.

Bagaimana ia berfungsi?

  1. Prafetch Bersyarat: Atribut prefetch (aktif secara lalai) mengawal sama ada pramuat akan dilakukan.

  2. Smart Cache: Satu Set digunakan untuk menyimpan pautan yang telah dimuat naik, mengelakkan panggilan berlebihan.

  3. Masuk Tetikus: Apabila pengguna menuding kursor pada pautan, fungsi handleMouseEnter menyemak sama ada pramuat perlu dan, jika ya, memulakan permintaan pengambilan ke destinasi.

  4. Ralat Selamat: Sebarang kegagalan dalam permintaan ditindas, memastikan gelagat komponen tidak terjejas oleh ralat rangkaian seketika.

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};

Apabila pengguna menuding tetikus pada pautan "Perihal Kami", komponen akan mula memuatkan data dari halaman /tentang, memberikan peralihan yang hampir serta-merta. Idea yang bernas, bukan? Tetapi saya melihatnya dalam dokumentasi react.dev.

app.useContext: Gerbang ke Edge

app.useContext ialah cangkuk asas React Edge, menyediakan akses kepada keseluruhan konteks pekerja:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}

Ciri Utama app.useContext

  • Pengurusan Laluan: Dapatkan akses kepada laluan yang sepadan, parameter dan rentetan pertanyaannya dengan mudah.
  • Penyepaduan RPC: Buat panggilan RPC yang ditaip dan selamat terus daripada pelanggan tanpa konfigurasi tambahan.
  • Akses Kedai Kongsi: Dapatkan semula atau tetapkan nilai dalam keadaan kongsi pekerja-klien dengan kawalan penuh ke atas keterlihatan (awam/swasta).
  • Akses URL Universal: Akses URL penuh permintaan semasa untuk pemaparan dan interaksi dinamik dengan mudah.

Mengapa Ia Berkuasa

Kait app.useContext merapatkan jurang antara pekerja dan pelanggan. Ia membolehkan anda membina ciri yang bergantung pada keadaan dikongsi, pengambilan data selamat dan pemaparan kontekstual tanpa kod berulang. Ini memudahkan aplikasi yang kompleks, menjadikannya lebih mudah untuk diselenggara dan lebih cepat untuk dibangunkan.

app.useUrlState: Negeri Disegerakkan dengan URL

Kait app.useUrlState memastikan keadaan aplikasi anda disegerakkan dengan parameter URL, memberikan anda kawalan tepat ke atas perkara yang disertakan dalam URL, cara keadaan itu disiri dan bila ia dikemas kini.

// Primeiro, definimos nossa API no servidor
class PropertiesAPI extends Rpc {
 async searchProperties(filters: PropertyFilters) {
   const results = await this.db.properties.search(filters);
   // Cache automático por 5 minutos
   return this.createResponse(results, {
     cache: { ttl: 300, tags: ['properties'] }
   });
 }

 async getPropertyDetails(ids: string[]) {
   return Promise.all(
     ids.map(id => this.db.properties.findById(id))
   );
 }
}

// Agora, no cliente, a mágica acontece
const PropertySearch = () => {
 const [filters, setFilters] = useState<PropertyFilters>({
   price: { min: 100000, max: 500000 },
   bedrooms: 2
 });

 // Busca reativa com debounce inteligente
 const { 
   data: searchResults,
   loading: searchLoading,
   error: searchError
 } = app.useFetch(
   async (ctx) => ctx.rpc.searchProperties(filters),
   {
     // Quando filters muda, refaz a busca
     deps: [filters],
     // Mas espera 300ms de 'silêncio' antes de buscar
     depsDebounce: {
       filters: 300
     }
   }
 );

 // Agora, vamos buscar os detalhes das propriedades encontradas
 const {
   data: propertyDetails,
   loading: detailsLoading,
   fetch: refreshDetails
 } = app.useFetch(
   async (ctx) => {
     if (!searchResults?.length) return null;

     // Isso parece fazer múltiplas chamadas, mas...
     return ctx.rpc.batch([
       // Na verdade, tudo é multiplexado em uma única requisição!
       ...searchResults.map(result => 
         ctx.rpc.getPropertyDetails(result.id)
       )
     ]);
   },
   {
     // Atualiza sempre que searchResults mudar
     deps: [searchResults]
   }
 );

 // Interface bonita e responsiva
 return (
   <div>
     <FiltersPanel 
       value={filters}
       onChange={setFilters}
       disabled={searchLoading}
     />

     {searchError && (
       <Alert status='error'>
         Erro na busca: {searchError.message}
       </Alert>
     )}

     <PropertyGrid
       items={propertyDetails || []}
       loading={detailsLoading}
       onRefresh={() => refreshDetails()}
     />
   </div>
 );
};

Parameter

  1. Keadaan Awal

    • Objek yang mentakrifkan struktur lalai dan nilai untuk keadaannya.
  2. Pilihan:

    • nyahpantun: Mengawal seberapa pantas URL dikemas kini selepas keadaan berubah.
    • sarung kebab: Menukar kunci keadaan kepada sarung kebab apabila bersiri ke URL.
    • omitKeys: Menentukan kunci untuk dikecualikan daripada URL.
    • omitValues: Nilai yang, apabila ada, akan mengecualikan kunci yang berkaitan daripada URL.
    • pickKeys: Hadkan keadaan bersiri untuk memasukkan kunci tertentu sahaja.
    • awalan: Menambah awalan pada semua parameter pertanyaan.
    • url: URL asas untuk penyegerakan, biasanya diperoleh daripada konteks aplikasi.

Faedah

  • Mesra SEO: Memastikan paparan bergantung kepada negeri ditunjukkan dalam URL yang boleh dikongsi.
  • Kemas kini dengan Debounce: Menghalang kemas kini pertanyaan yang berlebihan untuk input yang berubah dengan pantas.
  • URL Bersih: Pilihan seperti kebabCase dan omitKeys memastikan rentetan pertanyaan boleh dibaca.
  • Keadaan Penghidratan: Memulakan keadaan URL secara automatik apabila memasang komponen.
  • Berfungsi dalam semua persekitaran: Menyokong pemaparan bahagian pelayan dan penyemakan imbas sebelah pelanggan.

Aplikasi Praktikal

  • Penapis untuk Penyenaraian: Menyegerakkan penapis yang digunakan oleh pengguna dengan URL.
  • Paparan Dinamik: Memastikan zum peta, titik tengah atau tetapan lain berterusan.
  • Keutamaan Pengguna: Menyimpan tetapan yang dipilih ke URL untuk dikongsi.

app.useStorageState: Keadaan Berterusan

Kait app.useStorageState membolehkan anda mengekalkan keadaan dalam penyemak imbas menggunakan localStorage atau sessionStorage dengan sokongan menaip penuh.

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};

Pilihan Kegigihan

  • debounce: Mengawal kekerapan rakaman
  • storage: Pilih antara localStorage dan sessionStorage
  • omitKeys/pickKeys: Kawalan halus ke atas data berterusan

Prestasi

  • Kemas kini dioptimumkan dengan nyahlantun
  • Penyirian/penyahserilan automatik
  • Cache dalam ingatan

Kes Penggunaan Biasa

  • Sejarah carian
  • Senarai kegemaran
  • Keutamaan Pengguna
  • Status penapis
  • Keranjang beli-belah sementara
  • Draf borang

app.useDebounce: Kawalan Kekerapan

Nyahlantunkan nilai reaktif ​​dengan mudah:

// pages/api/search.ts
export default async handler = (req, res) => {
  // Configurar CORS
  // Validar request
  // Tratar erros
  // Serializar resposta
  // ...100 linhas depois...
}

// app/search/page.tsx
'use client';
import { useEffect, useState } from 'react';

export default const SearchPage = () => {
  const [search, setSearch] = useState('');
  const [filters, setFilters] = useState({});
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    let timeout;
    const doSearch = async () => {
      setLoading(true);
      try {
        const res = await fetch('/api/search?' + new URLSearchParams({
          q: search,
          ...filters
        }));
        if (!res.ok) throw new Error('Search failed');
        setData(await res.json());
      } catch (err) {
        console.error(err);
      } finally {
        setLoading(false);
      }
    };

    timeout = setTimeout(doSearch, 300);
    return () => clearTimeout(timeout);
  }, [search, filters]);

  // ... resto do componente
}

app.useDistinct: Nyatakan tanpa Pendua

Kekalkan tatasusunan nilai unik dengan menaip:

app.useDistinct ialah cangkuk khusus dalam mengesan apabila nilai sebenarnya telah berubah, dengan sokongan untuk perbandingan mendalam dan nyahlantun:

// No servidor
class UserAPI extends Rpc {
  async searchUsers(query: string, filters: UserFilters) {
    // Validação com Zod
    const validated = searchSchema.parse({ query, filters });
    return this.db.users.search(validated);
  }
}

// No cliente
const UserSearch = () => {
  const { rpc } = app.useContext<App.Context>();

  // TypeScript sabe exatamente o que searchUsers aceita e retorna!
  const { data, loading, error, fetch: retry } = app.useFetch(
    async (ctx) => ctx.rpc.searchUsers('John', { age: '>18' })
  );
};

Ciri-ciri Utama

  1. Pengesanan Nilai Berbeza:
    • Memantau nilai semasa dan sebelumnya
    • Mengesan secara automatik sama ada perubahan adalah penting berdasarkan kriteria anda
  2. Perbandingan Mendalam:
    • Mendayakan semakan kesaksamaan peringkat dalam untuk objek kompleks
  3. Perbandingan Diperibadikan:
    • Menyokong fungsi tersuai untuk mentakrifkan apa yang membentuk perubahan "berbeza"
  4. Melantun:
    • Mengurangkan kemas kini yang tidak perlu apabila perubahan berlaku terlalu kerap

Faedah

  • API yang sama untuk digunakanState: Mudah untuk disepadukan ke dalam komponen sedia ada.
  • Prestasi Dioptimumkan: Menghalang pengambilan semula atau pengiraan semula yang tidak perlu apabila nilai tidak berubah dengan ketara. UX yang dipertingkatkan: Menghalang kemas kini UI yang terlalu reaktif, menghasilkan interaksi yang lebih lancar.
  • Logik Ringkas: Menghapuskan semakan manual untuk kesamarataan atau pertindihan dalam pengurusan negeri.

Cakuk React Edge direka untuk berfungsi dengan harmoni, memberikan pengalaman pembangunan yang lancar dan ditaip. Menggabungkannya membolehkan anda mencipta antara muka yang kompleks dan reaktif dengan kod yang lebih sedikit.

The React Edge CLI: Kuasa di Hujung Jari Anda

React Edge CLI direka untuk memudahkan kehidupan pembangun dengan menghimpunkan alatan penting dalam satu antara muka yang intuitif. Sama ada anda seorang pemula atau pakar, CLI memastikan anda boleh mengkonfigurasi, membangun, menguji dan menggunakan projek dengan cekap dan tanpa kerumitan.

Ciri Utama

Perintah Modular dan Fleksibel:

  • bina: Membina kedua-dua apl dan pekerja, dengan pilihan untuk menentukan persekitaran dan mod pembangunan atau pengeluaran.
  • dev: Melancarkan pelayan pembangunan setempat atau jauh, membolehkan anda bekerja secara berasingan pada apl atau pekerja.
  • pengerahan: Melaksanakan penggunaan yang pantas dan cekap menggunakan kuasa gabungan Cloudflare Workers dan Cloudflare R2, memastikan prestasi dan kebolehskalaan pada infrastruktur tepi.
  • log: Pantau log pekerja terus dalam terminal.
  • lint: Mengautomasikan pelaksanaan Prettier dan ESLint, dengan sokongan untuk pembetulan automatik.
  • ujian: Menjalankan ujian dengan liputan pilihan menggunakan Vitest.
  • semakan taip: Mengesahkan penaipan TypeScript dalam projek.

Kes Penggunaan Pengeluaran

Saya berbangga untuk berkongsi bahawa aplikasi pengeluaran pertama menggunakan React Edge kini berfungsi! Ini ialah syarikat hartanah Brazil, Lopes Imóveis, yang sudah pun mengambil kesempatan daripada semua prestasi dan fleksibiliti rangka kerja.

Di tapak web agensi hartanah, hartanah dimuatkan dalam cache untuk mengoptimumkan carian dan menawarkan pengalaman yang lebih lancar untuk pengguna. Memandangkan ia adalah tapak web yang sangat dinamik, cache laluan menggunakan TTL selama 10 saat sahaja, digabungkan dengan strategi yang basi sementara pengesahan semula. Ini memastikan bahawa tapak menyampaikan data terkini dengan prestasi yang luar biasa, walaupun semasa pengesahan semula latar belakang.

Selain itu, pengesyoran untuk sifat yang serupa dikira dengan cekap dan sekali-sekala di latar belakang, dan disimpan terus dalam cache Cloudflare, menggunakan sistem cache yang disepadukan ke dalam RPC. Pendekatan ini mengurangkan masa tindak balas pada permintaan berikutnya dan membuat pengesyoran pertanyaan hampir serta-merta. Selain itu, semua imej disimpan pada Cloudflare R2, menawarkan storan berskala dan teragih tanpa bergantung pada pembekal luaran.

De Next.js a React Edge com Cloudflare Workers: Uma História de Libertação
De Next.js a React Edge com Cloudflare Workers: Uma História de Libertação

Dan tidak lama lagi kami juga akan mengadakan pelancaran projek pemasaran automatik yang besar untuk Easy Auth, seterusnya menunjukkan potensi teknologi ini.

Kesimpulan

Jadi, pembaca yang dihormati, kami sampai ke penghujung pengembaraan ini melalui alam semesta React Edge! Saya tahu masih terdapat banyak perkara yang luar biasa untuk diterokai, seperti pengesahan paling mudah seperti Asas dan Pembawa, dan rahsia kecil lain yang menjadikan kehidupan harian seorang pembangun lebih bahagia. Tetapi bertenang! Idea ini adalah untuk membawa artikel yang lebih terperinci pada masa hadapan untuk menyelami terlebih dahulu setiap ciri ini.

Dan, spoiler: tidak lama lagi React Edge akan menjadi sumber terbuka dan didokumenkan dengan betul! Mengimbangi pembangunan, kerja, penulisan dan sedikit kehidupan sosial bukanlah mudah, tetapi keseronokan melihat keajaiban ini dalam tindakan, terutamanya dengan kelajuan yang tidak masuk akal yang disediakan oleh infrastruktur Cloudflare, adalah bahan api yang menggerakkan saya. Jadi tahan kebimbangan anda, kerana yang terbaik akan datang! ?

Sementara itu, jika anda ingin mula meneroka dan menguji sekarang, pakej itu kini tersedia di NPM: React Edge pada NPM..

E-mel saya ialah feliperohdee@gmail.com, dan saya sentiasa terbuka untuk maklum balas, ini hanyalah permulaan perjalanan, cadangan dan kritikan membina ini. Jika anda menyukai apa yang anda baca, kongsikannya dengan rakan dan rakan sekerja anda dan nantikan perkara baharu yang akan datang. Terima kasih kerana mengikuti saya sejauh ini, dan sehingga kali seterusnya! ???

Atas ialah kandungan terperinci Dari Next.js untuk React Edge dengan Cloudflare Workers: A Liberation Story. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
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