
前の記事で、構成を必要とせず、インストール後すぐに戦闘の準備ができる新しいParcel bundlerについて説明しました。 しかし、資産の標準セットが十分にない場合はどうでしょうか? 答えは簡単です-独自のプラグインを作成します。
箱から次の資産を利用できることを思い出させてください。
- JavaScript(Babel)、CoffeeScript、TypeScript
- CSS、LESS、SASS、スタイラス
- HTML
- JSON、YAML
- グローブ、ロー
アセットを作成するには、2つの方法を選択できます。既存の方法( JSAsset 、 HTMLAssetなど)を使用します。この方法では、 Assetクラスをベースとして、ロジックの一部を書き換えたり追加したり、ゼロから書き込みます。
例として、 Pugのプラグインがどのように書かれたかを説明します 。
理論のビット
最初に、Parcelがプラグインでどのように機能し、何ができるのかを理解する必要がありますか?
バンドラーが初期化されると、パッケージはparcel-plugin-
始まるpackage.jsonで検索されます。 見つかった各バンドルパッケージは、エクスポートされた関数を接続して呼び出し、そのコンテキストを渡します。 この機能では、資産を登録できます。
私たちの資産は次のメソッドを実装する必要があります
parse(code: string): Ast collectDependencies(): void generate(): Object
また、オプションのメソッドを実装することもできます。
pretransform(): void transform(): void
Pug ASTの使用方法
ASTを操作するためのいくつかの公式パッケージがあります。
プラグイン
次のプロジェクト構造を作成します。
parcel-plugin-pug ├── package.json ├── src │ ├── PugAsset.ts │ ├── index.ts │ └── modules.d.ts ├── tsconfig.json └── tslint.json
index.ts
ファイルは、プラグインへのエントリポイントになります。
export = (bundler: any) => { bundler.addAssetType('pug', require.resolve('./PugAsset')); bundler.addAssetType('jade', require.resolve('./PugAsset')); };
アセットを操作するには、基本クラスAsset
が必要です。 必要なモジュールのTypeScriptバインディングを作成しましょう。
modules.d.ts declare module 'parcel-bundler/src/Asset' { class Asset { constructor(name: string, pkg: string, options: any); parse(code: string): any; addDependency(path: string, options: Object): any; addURLDependency(url: string): string; name: string; isAstDirty: boolean; contents: string; ast: any; options: any; dependencies: Set<Object>; } export = Asset; } declare module 'parcel-bundler/src/utils/is-url' { function isURL(url: string): boolean; export = isURL; } declare module 'pug-load' { class load { static string(str: string, options?: any): any; } export = load; } declare module 'pug-lexer' { class Lexer {} export = Lexer; } declare module 'pug-parser' { class Parser {} export = Parser; } declare module 'pug-walk' { function walkAST(ast: any, before?: (node: any, replace?: any) => void, after?: (node: any, replace?: any) => void, options?: any): void; export = walkAST; } declare module 'pug-linker' { function link(ast: any): any; export = link; } declare module 'pug-code-gen' { function generateCode(ast: any, options: any): string; export = generateCode; } declare module 'pug-runtime/wrap' { function wrap(template: string, templateName?: string): Function; export = wrap; }
PugAsset.ts
ファイルは、テンプレートファイルをHTMLに変換するための資産です。
import Asset = require('parcel-bundler/src/Asset'); export = class PugAsset extends Asset { public type = 'html'; constructor(name: string, pkg: string, options: any) { super(name, pkg, options); } public parse(code: string) { } public collectDependencies(): void { } public generate() { } };
テンプレートテキストをASTに変換することから始めましょう。 前にも言ったように、バンドラーはファイルに出くわすと、そのアセットを見つけようとします。 見つかった場合、 parse -> pretransform -> collectDependencies -> transform -> generate
呼び出しチェーンのparse -> pretransform -> collectDependencies -> transform -> generate
が発生します。 最初のステップは、 parse
メソッドを実装parse
ことです。
public parse(code: string) { let ast = load.string(code, {
次に、構築されたツリーを調べて、リンクを含む可能性のある要素を見つける必要があります。 操作のメカニズムは非常に単純で、標準のHTMLAsset
スパイされています。 一番下の行は、リンクを含む可能性のあるHTMLノードの属性を使用して辞書をコンパイルすることです。 ツリーを検索するとき、適切なノードを見つけて、属性のコンテンツにaddURLDependency
メソッドへのリンクをaddURLDependency
必要があります。このメソッドは、ファイル拡張子に応じて必要なアセットを見つけようとします。 アセットが見つかった場合、メソッドは新しいファイル名を返し、同時にこのファイルをアセンブリツリーに追加します(これにより、他のアセットのネストされた変換が発生します)。 古いパスの代わりにこの名前を使用する必要があります。 また、すべての接続ファイル( include
およびextends
)をこのアセットの依存関係として追加する必要があるという事実を考慮する必要があります。そうしないと、接続ファイルまたはベースファイルを変更するときに、テンプレート全体を再構築する必要がなくなります。
interface Dictionary<T> { [key: string]: T; } const ATTRS: Dictionary<string[]> = { src: [ 'script', 'img', 'audio', 'video', 'source', 'track', 'iframe', 'embed' ], href: ['link', 'a'], poster: ['video'] };
public collectDependencies(): void { walk(this.ast, node => {
最後の仕上げは、最終的なHTMLの取得です。 これはgenerate
メソッドの責任です:
public generate() { const result = generateCode(this.ast, {
すべてをまとめると、次のようになります。
PugAsset.ts import url = require('url'); import path = require('path'); import Asset = require('parcel-bundler/src/Asset'); import isURL = require('parcel-bundler/src/utils/is-url'); import load = require('pug-load'); import lexer = require('pug-lexer'); import parser = require('pug-parser'); import walk = require('pug-walk'); import linker = require('pug-linker'); import generateCode = require('pug-code-gen'); import wrap = require('pug-runtime/wrap'); interface Dictionary<T> { [key: string]: T; }
プラグインの準備ができました。 入力としてテンプレートを受け入れ、テキストをASTに変換し、すべての内部依存関係を解決し、既成のHTMLを生成し、組み込みのinclude
およびextends
コンストラクトを正しく認識しinclude
コンストラクトデータを含むテンプレート全体を再構築する方法を知っています。
マイナーな欠陥から-エラーが発生すると、テキストが複製されます。これはParcel出力の機能であり、 try catch
関数呼び出しをラップし、発信エラーを美しく出力します。
参照資料