Kompilasi dan bundel file MDX Anda dan dependensinya. CEPAT.
Anda memiliki string MDX dan berbagai file TS/JS yang digunakannya dan Anda ingin mendapatkan versi yang dibundel dari file -file ini untuk dievaluasi di browser.
Ini adalah fungsi async yang akan menyusun dan menggabungkan file MDX Anda dan ketergantungannya. Menggunakan MDX V3 dan EsBuild, jadi sangat cepat dan mendukung file TypeScript (untuk dependensi file MDX Anda).
File sumber Anda bisa lokal, dalam repo github jarak jauh, dalam CMS, atau di mana pun dan tidak masalah. Yang dipedulikan oleh mdx-bundler
adalah Anda meneruskan semua file dan kode sumber yang diperlukan dan akan mengurus menggabungkan semuanya untuk Anda.
MDX memungkinkan Anda untuk menggabungkan sintaks markdown singkat untuk konten Anda dengan kekuatan komponen reaksi. Untuk situs konten yang berat, menulis konten dengan HTML lurus dapat menjadi verbose yang mengganggu. Seringkali orang menyelesaikan ini menggunakan editor Wsywig, tetapi terlalu sering mereka gagal dalam memetakan niat penulis untuk HTML. Banyak orang lebih suka menggunakan Markdown untuk mengekspresikan sumber konten mereka dan diuraikan ke HTML untuk diberikan.
Masalah dengan menggunakan Markdown untuk konten Anda adalah jika Anda ingin memiliki beberapa interaktivitas yang tertanam dalam konten Anda, Anda cukup terbatas. Anda perlu memasukkan elemen yang ditargetkan JavaScript (yang sangat tidak langsung), atau Anda dapat menggunakan iframe
atau semacamnya.
Seperti yang dinyatakan sebelumnya, MDX memungkinkan Anda untuk menggabungkan sintaks markdown singkat untuk konten Anda dengan kekuatan komponen reaksi. Jadi Anda dapat mengimpor komponen bereaksi dan membuatnya dalam penurunan harga itu sendiri. Ini yang terbaik dari kedua dunia.
next-mdx-remote
?" mdx-bundler
sebenarnya menggabungkan dependensi file MDX Anda. Misalnya, ini tidak akan berfungsi dengan next-mdx-remote
, tetapi akan dengan mdx-bundler
:
--- Judul: Contoh pascaperang: 2021-02-13Description: Ini adalah beberapa deskripsi ---# demo WahooImport dari './demo' Ini demo ** rapi **: <Demo />
next-mdx-remote
tersedak impor itu karena itu bukan bundler, itu hanya kompiler. mdx-bundler
adalah kompiler dan bundler MDX. Itulah bedanya.
Alat -alat itu dimaksudkan untuk dijalankan "saat membangun" dan kemudian Anda menggunakan versi yang dibangun dari file Anda. Ini berarti jika Anda memiliki beberapa konten di MDX dan ingin membuat perubahan kesalahan ketik, Anda harus membangun kembali dan memulihkan seluruh situs. Ini juga berarti bahwa setiap halaman MDX yang Anda tambahkan ke situs Anda akan meningkatkan waktu bangunan Anda, sehingga tidak skala semuanya dengan baik.
mdx-bundler
pasti dapat digunakan pada waktu build, tetapi lebih kuat digunakan sebagai bundler runtime. Kasing penggunaan umum adalah memiliki rute untuk konten MDX Anda dan ketika permintaan itu masuk, Anda memuat konten MDX dan menyerahkannya ke mdx-bundler
untuk bundling. Ini berarti bahwa mdx-bundler
dapat diukur tanpa batas. Bangunan Anda tidak akan lagi terlepas dari berapa banyak konten MDX yang Anda miliki. Juga, mdx-bundler
cukup cepat, tetapi untuk membuat bundling sesuai permintaan ini lebih cepat, Anda dapat menggunakan header cache yang sesuai untuk menghindari pengundian ulang yang tidak perlu.
Webpack/rollup/dll juga mengharuskan semua file MDX Anda ada di sistem file lokal untuk berfungsi. Jika Anda ingin menyimpan konten MDX Anda dalam repo atau CMS terpisah, Anda agak kurang beruntung atau harus melakukan beberapa senam waktu build untuk mendapatkan file yang ada untuk dibangun.
Dengan mdx-bundler
, tidak masalah dari mana konten MDX Anda berasal, Anda dapat menggabungkan file dari mana saja, Anda hanya bertanggung jawab untuk memasukkan konten ke dalam memori dan kemudian Anda menyerahkannya ke mdx-bundler
untuk bundling.
Sama sekali. Ini bekerja dengan alat -alat itu. Bergantung pada apakah meta-kerangka Anda mendukung rendering sisi server, Anda akan mengimplementasikannya secara berbeda. Anda mungkin memutuskan untuk pergi dengan pendekatan waktu built-time (untuk Gatsby/CRA), tetapi seperti yang disebutkan, kekuatan sebenarnya dari mdx-bundler
datang dalam bentuk bundling on-demand. Jadi yang paling cocok untuk kerangka kerja SSR seperti Remix/Next.
Mengapa tidak?
Esbuild menyediakan layanan yang ditulis dalam perjalanan yang berinteraksi dengannya. Hanya satu contoh dari layanan ini yang dapat berjalan pada satu waktu dan harus memiliki versi yang identik dengan paket NPM. Jika itu adalah ketergantungan yang sulit, Anda hanya akan dapat menggunakan versi EsBuild MDX-Bundler.
Instalasi
Penggunaan
Opsi
Kembali
Tipe
Substitusi Komponen
Frontmatter dan Const
Mengakses ekspor bernama
Bundling gambar
Bundling file.
Komponen khusus dalam file hilir
Masalah yang diketahui
Inspirasi
Solusi lain
Masalah
? Serangga
Permintaan fitur
Kontributor
LISENSI
Modul ini didistribusikan melalui NPM yang dibundel dengan node dan harus diinstal sebagai salah satu dependencies
proyek Anda:
npm install --save mdx-bundler esbuild
Salah satu dependensi MDX-Bundler memerlukan pengaturan Node-GYP yang berfungsi untuk dapat menginstal dengan benar.
impor {bundlemdx} dari 'mdx-bundler'const mdxsource = `--- judul: Contoh pascaperang: 2021-02-13Description: Ini adalah beberapa deskripsi ---# wahooImport Demo dari' ./demo's a ** rapi* * Demo: <demo />`.trim() hasil hasil = menunggu bundemdx ({ Sumber: MDXSource, File: {'./demo.tsx': `impor * sebagai reaksi dari 'react'function demo () {return <div> demo rapi! </div>} ekspor demo default`, },}) const {code, frontMatter} = hasil
Dari sana, Anda mengirim code
ke klien Anda, dan kemudian:
impor * sebagai reaksi dari 'react'import {getMdxComponent} dari' mdx-bundler/klien'function post ({code, frontMatter}) { // umumnya ide yang baik untuk memoisasi panggilan fungsi ini // Hindari menciptakan kembali komponen setiap render. const component = react.usememo (() => getMdxComponent (kode), [kode]) return (<> <header> <h1> {frontmatter.title} </h1> <p> {frontmatter.description} </p> </ header> <action> <component/> </cain> </> )}
Pada akhirnya, ini diterjemahkan (pada dasarnya):
<Header> <h1> Ini adalah judul </h1> <p> Ini adalah beberapa deskripsi </p> </header> <action> <div> <h1> wahoo </h1> <p> Berikut adalah <strong> rapi </strong> demo: </p> <verv> demo rapi! </div> </div> </pain>
Sumber string
MDX Anda.
Tidak dapat diatur jika file
diatur
Jalur ke file pada disk Anda dengan MDX di. Anda mungkin ingin mengatur CWD juga.
Tidak dapat diatur jika source
disetel
Konfigurasi files
adalah objek dari semua file yang Anda bundling. Kunci adalah jalur ke file (relatif ke sumber MDX) dan nilainya adalah string kode sumber file. Anda bisa mendapatkannya dari sistem file atau dari database jarak jauh. Jika MDX Anda tidak merujuk file lain (atau hanya mengimpor sesuatu dari node_modules
), maka Anda dapat menghilangkan ini sepenuhnya.
Ini memungkinkan Anda untuk memodifikasi konfigurasi MDX bawaan (diteruskan ke @mdx-js/esbuild
). Ini dapat bermanfaat untuk menentukan pelaku/rehypePlugins Anda sendiri.
Fungsi dilewatkan mdxoptions default dan frontmatter.
bundlemdx ({ Sumber: MDXSource, MDXOptions (Opsi, FrontMatter) {// Ini adalah cara yang disarankan untuk menambahkan plugin komentar/rehype khusus: // Sintaksnya mungkin terlihat aneh, tetapi melindungi Anda jika kami menambahkan/melepas // plugin di masa depan.options.remarkplugins = [... (option.remarkplugins ?? []), myremarkplugin] opsi.rehypePlugins = [... (opsi.rehypePlugins ?? []), myrehypePlugin] opsi pengembalian },})
Anda dapat menyesuaikan opsi EsBuild dengan opsi esbuildOptions
. Ini mengambil fungsi yang dilewatkan opsi EsBuild default dan frontmatter dan mengharapkan objek opsi akan dikembalikan.
bundlemdx ({ Sumber: MDXSource, EsbuildOptions (opsi, frontmatter) {options.minify = falseOptions.target = ['ES2020', 'chrome58', 'firefox57', 'safari11', 'edge16', 'node12',] opsi pengembalian },})
Informasi lebih lanjut tentang opsi yang tersedia dapat ditemukan dalam dokumentasi EsBuild.
Disarankan untuk menggunakan fitur ini untuk mengonfigurasi target
ke output yang Anda inginkan, jika tidak, EsBuild default ke esnext
yang mengatakan bahwa itu tidak menyusun fitur standar sehingga ada kemungkinan pengguna browser yang lebih lama akan mengalami kesalahan.
Ini memberi tahu EsBuild bahwa modul yang diberikan tersedia secara eksternal. Misalnya, jika file MDX Anda menggunakan perpustakaan D3 dan Anda sudah menggunakan pustaka D3 di aplikasi Anda maka Anda akan berakhir mengirimkan d3
ke pengguna dua kali (sekali untuk aplikasi Anda dan sekali untuk komponen MDX ini). Ini sia -sia dan Anda akan lebih baik hanya memberi tahu Esbuild untuk tidak menggabungkan d3
dan Anda dapat meneruskannya ke komponen sendiri ketika Anda memanggil getMDXComponent
.
Opsi Konfigurasi Eksternal Global: https://www.npmjs.com/package/@fal-works/esbuild-plugin-global-externals
Inilah contohnya:
// Kode sisi server atau waktu yang berjalan di node: import {bundlemdx} dari 'mdx-bundler'const mdxsource = `# Ini adalah titleImport leftpad dari' Pad Left '<verv> {leftpad (" Demo Neat ! ", 12, '!')} </div>` .trim () const result = menunggu bundlemdx ({ Sumber: MDXSource, // Catatan: Ini * hanya * diperlukan jika Anda ingin berbagi deps di antara mdx Anda // Bundel file dan aplikasi host. Kalau tidak, semua DEP hanya akan dibundel. // Jadi itu akan berhasil, ini hanya optimasi untuk menghindari pengiriman // Beberapa salinan perpustakaan yang sama kepada pengguna Anda. Globals: {'Left-Pad': 'MyLeftPad'},})
// Server-Diberkir dan/atau kode sisi klien yang dapat berjalan di browser atau node: impor * sebagai react dari 'react'import leftpad dari' pad'import {getMdxComponent} dari 'mdx-bundler/client'function Mdxpage ({code}: {code: string}) { const component = react.usememo (() => getMdxComponent (result.code, {myleftpad: leftpad}), [result.code, leftpad], ) return (<cain> <component /> </cain> )}
Mengatur cwd
( Direktori Kerja Saat Ini ) ke Direktori akan memungkinkan EsBuild untuk menyelesaikan impor. Direktori ini bisa menjadi direktori konten MDX dibaca dari atau direktori yang harus dijalankan oleh MDX.
konten/halaman/demo.tsx
impor * sebagai reaksi dari 'react'function demo () { Kembalikan <VET> DEMO yang rapi! </div>} Ekspor Demo Default
src/build.ts
Impor {bundlemdx} dari 'mdx-bundler'const mdxsource = `--- judul: contoh pascaperang: 2021-02-13Description: Ini adalah beberapa deskripsi ---# wahooImport demo dari' ./demo's a ** rapi* * Demo: <demo />`.trim() hasil hasil = menunggu bundemdx ({ Sumber: MDXSource, CWD: '/Users/You/Situs/_content/halaman',}) const {code, frontMatter} = hasil
Ini memungkinkan Anda untuk mengonfigurasi opsi materi abu-abu.
Fungsi Anda dilewatkan konfigurasi materi abu-abu saat ini untuk Anda modifikasi. Kembalikan objek konfigurasi yang dimodifikasi untuk materi abu -abu.
bundlemdx ({ GrayMatterOptions: options => {options.excerpt = opsi truereturn },})
Ini memungkinkan Anda untuk mengatur direktori output untuk bundel dan URL publik ke direktori. Jika satu opsi diatur, yang lain juga harus.
Bundel JavaScript tidak ditulis ke direktori ini dan masih dikembalikan sebagai string dari bundleMDX
.
Fitur ini paling baik digunakan dengan tweak untuk mdxOptions
dan esbuildOptions
. Dalam contoh di bawah ini file .png
ditulis ke disk dan kemudian disajikan dari /file/
.
Ini memungkinkan Anda untuk menyimpan aset dengan MDX Anda dan kemudian meminta EsBuild memprosesnya seperti yang lainnya.
Direkomendasikan bahwa setiap bundel memiliki bundleDirectory
sendiri sehingga beberapa bundel tidak saling menimpa aset satu sama lain.
const {code} = menunggu bundlemdx ({ File: '/path/to/site/content/file.mdx', CWD: '/path/to/site/content', Bundledirectory: '/path/to/site/public/file', bundelpath: '/file/', mdxoptions: options => {options.remarkplugins = [komersimdximages] opsi pengembalian }, EsBuildOptions: options => {options.Loader = {... options.loader, '.png': 'file',} opsi pengembalian opsi },})
bundleMDX
mengembalikan janji untuk suatu objek dengan properti berikut.
code
- Bundel MDX Anda sebagai string
.
frontmatter
- object
frontmatter dari materi abu -abu.
matter
- seluruh objek yang dikembalikan oleh materi abu -abu
mdx-bundler
memasok ketik lengkap dalam paketnya sendiri.
bundleMDX
memiliki parameter tipe tunggal yang merupakan jenis frontmatter Anda. Itu default ke {[key: string]: any}
dan harus menjadi objek. Ini kemudian digunakan untuk mengetik frontmatter
yang dikembalikan dan frontmatter yang diteruskan ke esbuildOptions
dan mdxOptions
.
const {frontMatter} = bundlemdx <{title: string}> ({source}) frontMatter.title // memiliki tipe string
MDX Bundler meneruskan kemampuan MDX untuk mengganti komponen melalui components
prop pada komponen yang dikembalikan oleh getMDXComponent
.
Berikut adalah contoh yang menghapus t tag dari sekitar gambar.
impor * sebagai reaksi dari 'react'import {getMdxComponent} dari' mdx-bundler/client'const paragraf: react.fc = props => { if (typeOf props.children! == 'string' && props.children.type === 'img') {return <> {props.children} </> } return <p {... props} />} function mdxpage ({code}: {code: string}) { const component = react.usememo (() => getMdxComponent (kode), [kode]) return (<action> <component components = {{p: paragraf}} /> </cain> )}
Anda dapat merujuk frontmatter meta atau consts dalam konten MDX.
--- Judul: Contoh Posting --- Ekspor const exampleImage = 'https://example.com/image.jpg'# {frontmatter.title} <img src = {exampleImage} alt = "gambar alt teks"/>
Anda dapat menggunakan getMDXExport
alih -alih getMDXComponent
untuk memperlakukan file MDX sebagai modul, bukan hanya sebuah komponen. Dibutuhkan argumen yang sama seperti yang dilakukan getMDXComponent
.
--- Judul: Contoh posting --- Ekspor const toc = [{kedalaman: 1, nilai: 'judul'}]# judul
impor * sebagai react dari 'react'import {getMdxexport} dari' mdx-bundler/client'function mdxpage ({code}: {code: string}) { const mdxexport = getMDxExport (kode) console.log (mdxexport.toc) // [{kedalaman: 1, nilai: 'judul'}] const component = react.usememo (() => mdxexport.default, [kode]) return <component />}
Dengan CWD dan Plugin Komentar Komentar-MDX-Images Anda dapat menggabungkan gambar di MDX Anda!
Ada dua loader di Esbuild yang dapat digunakan di sini. Yang termudah adalah dataurl
yang mengeluarkan gambar sebagai URL data inline dalam kode yang dikembalikan.
Impor {KomentarmdxImages} dari 'komentar-mdx-images'const {code} = Await bundlemdx ({{{{{{{ Sumber: MDXSource, CWD: '/pengguna/Anda/situs/_content/halaman', mdxoptions: options => {options.remarkplugins = [... (options.remarkplugins ?? []), komersimdximages] opsi pengembalian }, EsBuildOptions: options => {options.Loader = {... options.loader, '.png': 'dataUrl',} opsi pengembalian },})
file
loader membutuhkan sedikit lebih banyak konfigurasi untuk dapat bekerja. Dengan loader file
, gambar Anda disalin ke direktori output sehingga EsBuild perlu diatur untuk menulis file dan perlu tahu di mana harus meletakkannya ditambah URL folder yang akan digunakan dalam sumber gambar.
Setiap panggilan ke
bundleMDX
diisolasi dari yang lain. Jika Anda mengatur direktori yang sama untuk semuabundleMDX
akan menimpa gambar tanpa peringatan. Akibatnya setiap bundel membutuhkan direktori outputnya sendiri.
// untuk file `_content/pages/sekitar.mdx`const {code} = menunggu bundlemdx ({{{{{{{{{ Sumber: MDXSource, CWD: '/pengguna/Anda/situs/_content/halaman', mdxoptions: options => {options.remarkplugins = [... (options.remarkplugins ?? []), komersimdximages] opsi pengembalian }, EsBuildOptions: options => {// Atur `outdir` ke lokasi umum untuk bundle.options.outdir = '/users/you/site/public/img/about'options.loader = {... Options.Loader ini , // Beri tahu EsBuild untuk menggunakan `file` loader untuk pngs '.png': 'file',} // atur jalur publik ke /img/aboutoptions.publicpath = '/img/tentang' // setel ke true Sehingga EsBuild akan mengeluarkan file file.options.write = truereturn },})
Jika file MDX Anda ada di disk Anda, Anda dapat menghemat waktu dan kode dengan meminta mdx-bundler
membaca file untuk Anda. Alih -alih menyediakan string source
, Anda dapat mengatur file
ke jalur MDX pada disk. Atur cwd
ke foldernya sehingga impor relatif berfungsi.
import {bundlemdx} dari 'mdx-bundler'const {code, frontMatter} = menunggu bundemdx ({{{{{{{{ File: '/users/you/site/content/file.mdx', CWD: '/pengguna/Anda/situs/konten/',})
Untuk memastikan komponen khusus dapat diakses dalam file MDX hilir, Anda dapat menggunakan MDXProvider
dari @mdx-js/react
untuk meneruskan komponen khusus ke impor bersarang Anda.
npm install --save @mdx-js/react
const globals = { '@mdx-js/react': {varname: 'mdxjsreact', bernama exports: ['useMdxComponents'], defaultExport: false, },}; const {code} = bundlemdx ({ sumber, global, mdxoptions (opsi: Rekam <string, any any>) {return {... options, providerImportSource: '@mdx-js/react',}; }});
Dari sana, Anda mengirim code
ke klien Anda, dan kemudian:
impor {mdxProvider, useMdxComponents} dari '@mdx-js/react'; const mdx_global_config = { Mdxjsreact: {usemdxComponents, },}; Ekspor const mdxComponent: react.fc <{ Kode: String; FrontMatter: Rekam <string, any any>;}> = ({code}) => { const component = useMeMo (() => getMdxComponent (kode, mdx_global_config), [kode], ); return (<mdxProvider components = {{text: ({anak -anak}) => <p> {anak -anak} </p>}}> <component/> </mdxprovider> );};
Kami ingin ini bekerja di CloudFlare Workers. Sayangnya Cloudflares memiliki dua batasan yang mencegah mdx-bundler
bekerja di lingkungan itu:
Pekerja tidak bisa menjalankan binari. bundleMDX
menggunakan esbuild
(biner) untuk menggabungkan kode MDX Anda.
Pekerja tidak dapat menjalankan eval
atau serupa. getMDXComponent
mengevaluasi kode yang dibundel menggunakan new Function
.
Salah satu solusi untuk ini adalah menempatkan kode terkait MDX-Bundler Anda di lingkungan yang berbeda dan menyebut lingkungan itu dari dalam pekerja CloudFlare. IMO, ini mengalahkan tujuan menggunakan CloudFlare Workers. Solusi potensial lainnya adalah menggunakan Wasm dari dalam pekerja. Ada esbuild-wasm
tetapi ada beberapa masalah dengan paket yang dijelaskan di tautan itu. Lalu ada wasm-jseval
, tetapi saya tidak bisa menjalankan kode yang merupakan output dari mdx-bundler
tanpa kesalahan.
Jika seseorang ingin menggali ini, itu akan menjadi bintang, tetapi sayangnya tidak mungkin saya akan mengerjakannya.
Esbuild mengandalkan __dirname
untuk mencari tahu di mana dapat dieksekusi, Next.js dan Webpack kadang -kadang dapat merusak ini dan Esbuild perlu diberitahu secara manual di mana harus mencari.
Menambahkan kode berikut sebelum bundleMDX
Anda akan mengarahkan Esbuild secara langsung pada yang dapat dieksekusi dengan benar untuk platform Anda.
Impor Path dari 'Path'if (Process.Platform ===' Win32 ') { process.env.esbuild_binary_path = path.join (process.cwd (), 'node_modules', 'esbuild', 'esbuild.exe', )} kalau tidak { process.env.esbuild_binary_path = path.join (process.cwd (), 'node_modules', 'esbuild', 'bin', 'esbuild', )}
Informasi lebih lanjut tentang masalah ini dapat ditemukan dalam artikel ini.
Ketika saya menulis ulang kentcdodds.com untuk remix, saya memutuskan ingin mempertahankan posting blog saya sebagai MDX, tetapi saya tidak ingin harus mengkompilasi semuanya pada waktu pembangunan atau diminta untuk menggunakan kembali setiap kali saya memperbaiki kesalahan ketik. Jadi saya membuat ini yang memungkinkan server saya untuk mengkompilasi permintaan.
Ada MDX-Remote Next tetapi lebih merupakan kompiler MDX daripada bundler (tidak dapat menggabungkan MDX Anda untuk dependensi). Juga difokuskan pada next.js sedangkan ini adalah meta-kerangka agnostik.
Ingin berkontribusi? Cari label edisi pertama yang bagus.
Harap ajukan masalah untuk bug, dokumentasi yang hilang, atau perilaku yang tidak terduga.
Lihat bug
Harap ajukan masalah untuk menyarankan fitur baru. Pilih permintaan fitur dengan menambahkan? Ini membantu pengelola memprioritaskan apa yang harus dikerjakan.
Lihat Permintaan Fitur
Terima kasih kepada orang -orang ini (Kunci Emoji):
Kent C. Dodds ? | Benwis ? ? | Adam Laycock | Titus ? ? | Christian Murphy ? | Pedro Duarte | Erik Rasmussen |
Omar Syx ? | Gaël Haméon | Gabriel Loiácono | Spencer Miskoviak | Casper | Apostolos Christodoulou | Yordis Prieto |
xoumi | Yasin | Mohammed 'Mo' Mulazada | Bisa rau | Hosenur Rahaman | Maciek Sitkowski | Priyang |
Mosaad | StefanProbst | Vlad Moroz |
Proyek ini mengikuti spesifikasi semua-kontributor. Kontribusi apa pun yang baik!
Mit