MDXファイルとその依存関係をコンパイルしてバンドルします。速い。
使用するMDXの文字列とさまざまなTS/JSファイルがあり、ブラウザで評価するためにこれらのファイルのバンドルバージョンを取得したいと考えています。
これは、MDXファイルとその依存関係をコンパイルおよびバンドルする非同期関数です。 MDX V3とEsBuildを使用するため、非常に高速でタイプスクリプトファイル(MDXファイルの依存関係)をサポートします。
ソースファイルは、リモートGithubリポジトリ、CMS、または他の場所でローカルになる可能性があります。 mdx-bundler
気にするすべてのことは、必要なすべてのファイルとソースコードを渡すことであり、あなたのためにすべてをバンドすることに注意します。
MDXを使用すると、コンテンツのTerse Markdown構文をReactコンポーネントのパワーと組み合わせることができます。コンテンツが多いサイトの場合、ストレートアップHTMLでコンテンツを書くことは迷惑に冗談です。多くの場合、人々はWsywigの編集者を使用してこれを解決しますが、多くの場合、多くの場合、作家のHTMLへの意図をマッピングするのに不足しています。多くの人々は、マークダウンを使用してコンテンツソースを表現し、レンダリングするためにHTMLに解析されていることを好みます。
コンテンツにMarkdownを使用することの問題は、コンテンツにインタラクティブに埋め込まれたい場合、かなり限られていることです。 JavaScriptがターゲットをターゲットにする要素を挿入する必要があるか(これは迷惑に間接的です)、 iframe
などを使用することができます。
前述のように、MDXは、コンテンツのTerse Markdown構文をReactコンポーネントの力と組み合わせることができます。そのため、Reactコンポーネントをインポートして、マークダウン自体内でレンダリングできます。それは両方の世界の中で最高です。
next-mdx-remote
とどう違うのですか?」 mdx-bundler
実際にMDXファイルの依存関係をバンドルします。たとえば、これはnext-mdx-remote
では機能しませんが、 mdx-bundler
では機能します。
---タイトル:example postpublished:2021-02-13description:これはいくつかの説明です---#wahooimportデモ './demo' これが**きれいな**デモです: <demo />
next-mdx-remote
バンドラーではなく、単なるコンパイラであるため、そのインポートを窒息させます。 mdx-bundler
MDXコンパイラとバンドラーです。それが違いです。
これらのツールは「ビルド時に」実行されることを目的としており、ファイルのビルドバージョンを展開します。これは、MDXにコンテンツがあり、タイプミスの変更を行いたい場合、サイト全体を再構築して再展開する必要があることを意味します。これはまた、サイトに追加するすべてのMDXページがビルドタイムを増加させるため、それほどうまくスケーリングされないことを意味します。
mdx-bundler
間違いなくビルドタイムで使用できますが、ランタイムバンドラーとしてより強力に使用されています。一般的なユースケースは、MDXコンテンツのルートを用意し、そのリクエストが入ったときに、MDXコンテンツをロードし、それをバンドルのためにmdx-bundler
にロードします。これはmdx-bundler
が無限にスケーラブルであることを意味します。 MDXコンテンツの量に関係なく、ビルドはこれ以上ありません。また、 mdx-bundler
非常に高速ですが、このオンデマンドバンドルをさらに速くするために、適切なキャッシュヘッダーを使用して、不必要な再バンドルを避けることができます。
Webpack/lollup/etcも、すべてのMDXファイルがローカルファイルシステム上に機能する必要があります。 MDXコンテンツを別のリポジトリまたはCMSに保存したい場合は、運が良くないか、ビルドのファイルを設置するためにビルドタイム体操を行う必要があります。
mdx-bundler
を使用すると、MDXコンテンツがどこから来たのかは関係ありません。どこからでもファイルをバンドルできます。コンテンツをメモリに入れるだけで、バンドリングのためにmdx-bundler
に渡します。
完全に。これらのツールのいずれかで動作します。メタフレームワークがサーバー側のレンダリングをサポートするかどうかに応じて、それを異なって実装します。 (ギャツビー/CRAの場合)構築されたアプローチを使用することを決定するかもしれませんが、前述のように、 mdx-bundler
の真の力はオンデマンドバンドルの形で提供されます。そのため、Remix/NextのようなSSRフレームワークに最適です。
なぜだめですか?
Esbuildは、Goが相互作用するサービスを提供しています。このサービスの1つのインスタンスのみが一度に実行され、NPMパッケージと同一のバージョンが必要です。それが難しい依存関係であれば、MDX-Bundlerが使用するEsbuildバージョンのみを使用できます。
インストール
使用法
オプション
返品
種類
コンポーネント置換
FrontMatterとconst
名前付きエクスポートにアクセスします
画像バンドル
ファイルのバンドル。
ダウンストリームファイルのカスタムコンポーネント
既知の問題
インスピレーション
その他のソリューション
問題
?バグ
機能リクエスト
貢献者
ライセンス
このモジュールは、ノードにバンドルされているNPMを介して配布され、プロジェクトのdependencies
の1つとしてインストールする必要があります。
npm install --save mdx-bundler esbuild
MDXバンドラーの依存関係の1つでは、正しくインストールできるように作業ノードGYPセットアップが必要です。
'mdx-bundler'const mdxsource = `--- title:example postpublished:2021-02-13description:これはいくつかの説明です - #wahooimport demo from' ./demo'here's a ** neat* * demo:<demo /> `.trim()const result = wait bundlemdx({{ 出典:mdxsource、 ファイル:{'./demo.tsx': `Import * as 'React'Function demo(){return <div> neat demo!</div>} exportデフォルトデモ`、 }、})const {code、frontmatter} = result
そこから、クライアントにcode
送信し、次のとおりです。
'racep'import {getmdxComponent}からのreact *' mdx-bundler/client'function post({code、frontmatter}){ //一般的に、この関数呼び出しをメモ化することは良い考えです //レンダリングごとにコンポーネントを再作成しないでください。 const Component = React.usememo(()=> getmdxComponent(code)、[code]) return(<> <header> <h1> {frontmatter.title} </h1> <p> {frontmatter.description} </p> </header> <main> <component/> </main> </> )}
最終的に、これは(基本的に)レンダリングされます。
<ヘッダー> <h1>これはタイトル</h1>です <p>これはいくつかの説明です</p> </header> <main> <div> <h1> wahoo </h1> <p>これは<strong> neat </strong> demo:</p> <div>きちんとしたデモ!</div>です </div> </main>
MDXのstring
ソース。
file
が設定されている場合、設定できません
MDXを使用したディスク上のファイルへのパス。おそらくCWDも設定する必要があります。
source
が設定されている場合、設定できません
files
構成は、バンドしているすべてのファイルのオブジェクトです。キーはファイルへのパス(MDXソースに対する)であり、値はファイルソースコードの文字列です。これらをファイルシステムまたはリモートデータベースから取得できます。 MDXが他のファイルを参照していない場合(またはnode_modules
からのみものをインポートします)、これを完全に省略できます。
これにより、組み込みのMDX構成( @mdx-js/esbuild
に渡されます)を変更できます。これは、独自の声次上の声数/rehypepluginを指定するのに役立ちます。
関数は、デフォルトのMDXOPTIONSとFrontMatterに渡されます。
bundlemdx({ 出典:mdxsource、 mdxoptions(options、frontmatter){//これは、カスタム覚醒/rehypeプラグインを追加する推奨される方法です://構文は奇妙に見えるかもしれませんが、future.options.remarkpluginsに//プラグインを追加/削除する場合にあなたを保護します= [...(options.remarkplugins ?? [])、myremarkplugin] options.rehypeplugins = [...(options.rehypeplugins ?? [])、myrehypeplugin] return options }、})
オプションesbuildOptions
を使用して、esbuildオプションのいずれかをカスタマイズできます。これにより、デフォルトのESBUILDオプションとFrontMatterに渡され、オプションオブジェクトが返されることを期待する関数が取得されます。
bundlemdx({ 出典:mdxsource、 esbuildoptions(options、frontmatter){options.minify = falseoptions.target = ['es2020'、 'chrome58'、 'firefox57'、 'safari11'、 'edge16'、 'node12'、] return options }、})
利用可能なオプションの詳細については、ESBUILDドキュメントをご覧ください。
この機能を使用して目的の出力にtarget
を構成することをお勧めします。そうしないと、esbuildはesnext
にデフォルトであり、標準化された機能をコンパイルしないため、古いブラウザーのユーザーがエラーを発生させる可能性があります。
これにより、特定のモジュールが外部から利用可能であることをEsBuildに伝えます。たとえば、MDXファイルがD3ライブラリを使用していて、アプリでD3ライブラリを既に使用している場合、 d3
ユーザーに2回出荷することになります(アプリ用に1回、このMDXコンポーネントに1回)。これは無駄であり、esbuildにd3
バンドルしないように伝えるだけで、 getMDXComponent
に電話するときに自分でコンポーネントに渡すことができます。
グローバルな外部構成オプション:https://www.npmjs.com/package/@fal-works/esbuild-plugin-global-externals
これが例です:
//ノードで実行されるサーバーサイドまたはビルドタイムコード: 'mdx-bundler'const mdxsource = `#これは' left-pad '<> {leftpad(" neat demo ! "、12、 '!')} </div>` .trim()const result = wait bundlemdx({{ 出典:mdxsource、 //注:MDX間でDEPを共有したい場合にこれは *のみ必要です * //ファイルバンドルとホストアプリ。それ以外の場合、すべてのDEPがバンドルされます。 //それはどちらの方法でも機能します、これは送信を避けるための単なる最適化です //ユーザーへの同じライブラリの複数のコピー。 グローバル:{'left-pad': 'myleftpad'}、})
//ブラウザまたはノードで実行できるサーバーレンダリングおよび/またはクライアント側のコード: 'ract'import leftpadからの' reft-pad'import {getMdxComponent}からの 'race'import leftpadからのインポート * mdx-bundler/client'function mdxpage({code}:{code:string}){ const component = ruce.usememo(()=> getmdxComponent(result.code、{myleftpad:leftpad})、[result.code、leftpad]、 )) return(<main> <component /> < /main> )}
cwd
(現在の作業ディレクトリ)をディレクトリに設定すると、ESBUILDがインポートを解決できます。このディレクトリは、MDXコンテンツが読み取られたディレクトリまたはオフディスクMDXを実行するディレクトリである可能性があります。
コンテンツ/ページ/demo.tsx
'React'Function demo()からの反応として *インポート * { return <div>きれいなデモ!</div>}デフォルトデモをエクスポートします
src/build.ts
'mdx-bundler'const mdxsource = `--- title:example postpublished:2021-02-13description:これはいくつかの説明です - #wahooimport demo from' ./demo'here's a ** neat* * demo:<demo /> `.trim()const result = wait bundlemdx({{ 出典:mdxsource、 cwd: '/users/you/site/_content/pages'、})const {code、frontmatter} = result
これにより、灰色のオプションを構成できます。
あなたの関数は、あなたが変更するための現在の灰色の構成に渡されます。修正された構成オブジェクトを灰白質のために返します。
bundlemdx({ graymatteroptions:options => {options.excerpt = truereturn options }、})
これにより、バンドルの出力ディレクトリとパブリックURLをディレクトリに設定できます。 1つのオプションが設定されている場合、もう1つのオプションも同様に必要です。
JavaScriptバンドルはこのディレクトリに書き込まれておらず、 bundleMDX
の文字列としてまだ返されます。
この機能は、 mdxOptions
およびesbuildOptions
の微調整で最適です。以下の例では、 .png
ファイルはディスクに書き込まれ、 /file/
から提供されます。
これにより、MDXで資産を保存し、他のものと同じようにEsBuildを処理させることができます。
複数のバンドルが互いの資産を上書きしないように、各バンドルに独自のbundleDirectory
を持つことをお勧めします。
const {code} = await bundlemdx({ ファイル: '/path/to/site/content/file.mdx'、 cwd: '/path/to/site/content'、 bundledirectory: '/path/to/site/public/file'、 bundlepath: '/file/'、 mdxoptions:options => {options.remarkplugins = [dermaymdximages] return options }、 esbuildoptions:options => {options.loader = {... options.loader、 '.png': 'file'、} return options }、})
bundleMDX
次のプロパティを持つオブジェクトの約束を返します。
code
- string
としてのMDXのバンドル。
frontmatter
灰色のfrontmatter object
。
matter
- 灰色で返されるオブジェクト全体
mdx-bundler
独自のパッケージ内の完全なタイピングを供給します。
bundleMDX
は、フロントマッティングのタイプである単一のタイプパラメーターがあります。デフォルトは{[key: string]: any}
になり、オブジェクトである必要があります。これは、返されたfrontmatter
入力するために使用され、フロントマッテルはesbuildOptions
とmdxOptions
に渡されます。
const {frontmatter} = bundlemdx <{title:string}>({source})frontmatter.title //は型文字列を持っています
MDXバンドラーは、 getMDXComponent
によって返されたコンポーネントのcomponents
PROPを介してコンポーネントを置き換えるMDXの能力に合格します。
周囲の画像からPタグを削除する例を次に示します。
'racep'import {getMdxComponent}からのreact * from' mdx-bundler/client'constパラグラフ:race.fc = props => { if(typeof props.children!== 'string' && propss.children.type == 'img'){return <> {propss.children} </> } return <p {... props} />} function mdxpage({code}:{code:string}){ const Component = React.usememo(()=> getmdxComponent(code)、[code]) return(<main> <Component Components = {{p:paragraph}} /> < /main> )}
MDXコンテンツでFrontMatterメタまたはconstsを参照できます。
---タイトル:例:const const exampleimage = 'https://example.com/image.jpg'# {frontmatter.title} <img src = {emblyimage} alt = "image alt text"/>>
getMDXComponent
の代わりにgetMDXExport
使用して、MDXファイルを単なるコンポーネントではなくモジュールとして扱うことができます。 getMDXComponent
行うのと同じ引数が必要です。
---タイトル:例:const toc = [{dept:1、value: 'the title'}]#const const toc = [{dept:1、value: 'the title'}]
Import * 'React'import {getMdxExport}からのReact As' MDX-Bundler/Client'Function Mdxpage({code}:{code:string}){{code}){ const mdxexport = getmdxexport(code) console.log(mdxexport.toc)// [{dept:1、value: 'the title'}] const Component = React.usememo(()=> mdxexport.default、[code]) return <component />}
CWDとLearm Plugin arem-mdx-imagesを使用すると、mdxに画像をバンドルできます!
Esbuildには、ここで使用できる2つのローダーがあります。最も簡単なのは、返されたコードのインラインデータURLとして画像を出力するdataurl
です。
'arem-mdx-images'const {code} = await bundlemdx({{code}から{aremmdximages}をimport { 出典:mdxsource、 cwd: '/users/you/site/_content/pages'、 mdxoptions:options => {options.remarkplugins = [...(options.remarkplugins ?? []、aremmdximages] return options }、 esbuildoptions:options => {options.loader = {... options.loader、 '.png': 'dataurl'、} return options }、})
file
ローダーは、機能するためにもう少し構成が必要です。 file
ローダーを使用すると、画像が出力ディレクトリにコピーされるため、esbuildを作成するために設定する必要があり、それらをどこに配置するかを知る必要があります。
bundleMDX
への各呼び出しは、他のものから分離されています。ディレクトリを設定した場合、すべての場合、bundleMDX
警告なしに画像を上書きします。その結果、各バンドルには独自の出力ディレクトリが必要です。
//ファイルの場合 `_content/pages/about.mdx`const {code} = await bundlemdx({{ 出典:mdxsource、 cwd: '/users/you/site/_content/pages'、 mdxoptions:options => {options.remarkplugins = [...(options.remarkplugins ?? []、aremmdximages] return options }、 esbuildoptions:options => {//「oututdir」をこのbundle.options.outdir = '/users/you/site/public/img/about'options.loader = {... options.loader 、// esbuildにpngs '.png'に `file`ローダーを使用するように指示します: 'file'、} // publicパスを/img/aboutoptions.publicpath = '/img/about'に設定しますesbuildがfiles.options.write = truereturnオプションを出力するように }、})
MDXファイルがディスク上にある場合は、 mdx-bundler
にファイルを読んでもらうことで、時間とコードを節約できます。 source
文字列を提供する代わりに、ディスク上のMDXのパスにfile
設定できます。 cwd
フォルダーに設定して、相対的なインポートが機能するようにします。
'mdx-bundler'const {code、frontmatter} = await bundlemdxから{bundlemdx}をimport {bundlemdx}({{ ファイル: '/users/you/site/content/file.mdx'、 cwd: '/users/you/site/content/'、})
ダウンストリームMDXファイルでカスタムコンポーネントにアクセスできるようにするには、 @mdx-js/react
のMDXProvider
使用して、ネストされたインポートにカスタムコンポーネントを渡すことができます。
npm install --save @mdx-js/react
const globals = { '@mdx-js/race':{varname: 'mdxjsReact'、namedexports:['usemdxcomponents']、defaultexport:false、 }、}; const {code} = bundlemdx({ ソース、 グローバル、 mdxoptions(options:record <string、any>){return {... options、providerimportsource: '@mdx-js/React'、}; }});
そこから、クライアントにcode
送信し、次のとおりです。
'@mdx-js/React'; const mdx_global_config = {from {mdxprovider、usemdxcomponents}をimport {usemdxcomponents} mdxjsReact:{usemdxComponents、 }、};エクスポートconst mdxComponent:React.fc <{ コード:文字列; frontmatter:record <string、any>;}> =({code})=> { const component = usememo(()=> getmdxComponent(code、mdx_global_config)、[code]、 ); return(<mdxprovider components = {{text:({children})=> <p> {children} </p>}}> <component/> </mdxprovider> );};
これがCloudFlareの労働者で働くことを望んでいます。残念ながら、CloudFlaresには、 mdx-bundler
その環境で機能することを妨げる2つの制限があります。
労働者はバイナリを実行できません。 bundleMDX
esbuild
(バイナリ)を使用してMDXコードをバンドルします。
労働者はeval
を実行できません。 getMDXComponent
new Function
を使用してバンドルされたコードを評価します。
これの1つの回避策は、MDXバンドラー関連のコードを別の環境に配置し、CloudFlareワーカー内からその環境を呼び出すことです。 IMO、これはCloudFlareワーカーを使用する目的を打ち負かします。別の潜在的な回避策は、労働者内からWASMを使用することです。 esbuild-wasm
はありますが、そのリンクで説明されているパッケージにはいくつかの問題があります。その後、 wasm-jseval
がありますが、エラーなしでmdx-bundler
から出力されたコードを実行することはできませんでした。
誰かがこれを掘り下げたいと思うなら、それは素晴らしいことですが、残念ながら私がそれに取り組むことはまずありません。
Esbuildは、 __dirname
に依存して実行可能な場所を作成するために、next.jsとwebpackがこれを破ることがあり、Esbuildはどこを見るかを手動で伝える必要があります。
bundleMDX
の前に次のコードを追加すると、プラットフォームの正しい実行可能ファイルにESBUILDを直接ポイントします。
'path'ifからパスをインポートする(process.platform ===' win32 '){ process.env.esbuild_binary_path = path.join(process.cwd()、 'node_modules'、 'esbuild'、 'esbuild.exe'、 )} それ以外 { process.env.esbuild_binary_path = path.join(process.cwd()、 'node_modules'、 'esbuild'、 'bin'、 'esbuild'、 )}
この問題の詳細については、この記事をご覧ください。
kentcdoddds.comをリミックスに書き直していたので、ブログの投稿をMDXとして保持したいと思いましたが、タイプミスを修正するたびにすべてをコンパイルしたり、再展開する必要がありませんでした。そこで、私はこれを作成しました。これにより、サーバーがオンデマンドでコンパイルできます。
Next-MDX-Remoteはありますが、バンドラーというよりはMDXコンパイラのようなものです(依存関係のためにMDXを束ねることはできません)。また、next.jsに焦点を合わせていますが、これはメタフレームワーク不可知論者です。
貢献したいですか?良い最初の問題ラベルを探してください。
バグ、不足しているドキュメント、または予期しない動作について問題を提出してください。
バグを参照してください
新機能を提案するために問題を提出してください。 ?を追加して、機能リクエストに投票してください。これにより、メンテナーは何に取り組むべきかを優先順位付けするのに役立ちます。
機能リクエストを参照してください
これらの人々に感謝します(絵文字キー):
ケントC.ドッズ ? | ベンウィス ? ? | アダム・レイコック | タイタス ? ? | クリスチャンマーフィー ? | ペドロ・ドゥアルテ | エリック・ラスムッセン |
オマール・シックス ? | ガエル・ハメオン | ガブリエル・ロアコーノ | スペンサー・ミスコビアック | キャスパー | アポストロス・クリストドゥール | ヨルディス・プリエト |
Xoumi | ヤシン | モハメッド「MO」ムラザダ | rauできます | Hosenur Rahaman | Maciek Sitkowski | プリヤン |
モザード | Stefanprobst | Vlad Moroz |
このプロジェクトは、全委員会の仕様に従います。あらゆる種類の貢献を歓迎します!
mit