ホームページ > 記事 > ウェブフロントエンド > Gulp の高度なカスタマイズされた gulp プラグイン_html/css_WEB-ITnose
gulp は多くのプロジェクトの標準となっており、gulp プラグイン エコシステムも非常に繁栄しています。2015.1.5 の時点で、npm には 10,190 の gulp プラグインが使用できます。完全に確実なビルドを組み立てることができます。
しかし、ドキュメントに従って最終的にプラグインを呼び出し、対応するパラメーターを渡しても、結果が期待どおりではないことが判明し、この時点でトラブルシューティングが必要になるという状況によく遭遇します。これは、gulp プラグインがどのように機能するかをある程度理解する必要があります。この記事では、gulp プラグインの実装を例として、gulp プラグインがどのように機能するかを説明します。
通常、構築リソースは js/css/html およびその他のリソース ファイルですが、開発またはリリースの段階で、js/css はマージ、圧縮、名前変更されます。他の処理ステップ。
場合によっては、構築後に生成される js/css の名前や数量を決定できないため、HTML ファイルにリソースの参照アドレスを記述することができません。それを使用するには、最終的に生成されたリソース ファイル/アドレスを HTML に挿入するのはどうでしょうか?
実装する必要があるプラグインが次のように使用されているとします。
<html><head> <!--InlineResource:\.css$--></head><body> <!--InlineResource:\.js$--></body></html>
HTML コメントを使用して、依存する必要があるリソースを宣言します。 InlineResource は単語を一致させるための鍵であり、「:」は区切り文字として使用され、/*.css$/、/*.js$/ は依存するファイルを宣言するための通常の一致です。
gulpfile.js では、ここで設定する必要があります:
gulp.task('dist', function () { return gulp.src('index.html') .pipe(InjectResources( gulp.src(['*.js', '*.css']) .pipe(hash(/*添加MD5作为文件名*/)) )) .pipe(gulp.dest('dist'))})
いくつかの方法と手順を簡単に紹介します:
gulp.src('index.html') は、ファイル システムの現在のディレクトリにあるindex.html を読み取り、後続のステップで使用する読み取り可能なストリームを生成します
InjectResources(stream) は、HTML に挿入される JS/CSS を取得するためのパラメーターを受け取ります。このパラメーターは、受信および受信用の Stream インスタンスを生成するために使用されます。前の手順でストリーミングされたデータを処理します。
hash(options) は、現在のストリームのファイル名に md5 文字列を追加するために使用されるサードパーティのプラグインです。 : gulp-hash
gulp.dest('dist') は、リソースを現在のディレクトリに挿入した後に HTML ファイルを生成するために使用されます
私たちが注意する必要があるのは 2 番目のポイントです。すべてのリソース ファイルを受信し、インジェクションを完了する方法は次のとおりです。
このロジックは 4 つのステップに分けることができます
プログラムを開始する前に、重要なサードパーティ ライブラリに依存する必要があります:map- stream
map-stream は、現在のストリーム内の各ファイル データを取得し、データの内容を変更するために使用されます。
module.exports = function (resourcesStream) { // step 1: TODO => 这里要获取所有的js/css资源}
リソース ストリームは、非同期インスタンスを通じて取得されるパラメーターとして InjectResources メソッドに渡されます。
var resources = []function getResources(done) { if (resources) return done(resources) // 由于下面的操作是异步的,此处要有锁... resourcesStream.pipe(mapStream(function (data, cb) { resources.push(data) cb(null, data) })) .on('end', function () { done(resources) })}
注: MapStream 処理メソッドの cb メソッド、2 番目のパラメータは置換に使用できます 現在処理されていますファイル オブジェクト
この時点で、カプセル化の最初のステップが完了しました。
module.exports = function (resourcesStream) { // step 1: function getResources () { ... }}
module.exports = function (resourcesStream) { // step 1: ✔︎ // step 2: TODO => 获取当前流中的所有目标HTML文件 return mapStream(function (data, cb) { })}
InjectResources プラグイン メソッドは、受信用の Writable Stream インスタンスを返します。 InjectResources にストリーミングされた HTML ファイルを処理する場合、mapStream の戻り値は書き込み可能なストリームです。
このとき、mapStream処理メソッドで取得したデータはHTMLファイルオブジェクトとなり、その内容が処理されます。
module.exports = function (resourcesStream) { // step 1: ✔︎ // step 2: ✔ return mapStream(function (data, cb) { var html = data.contents.toString() // step 3: TODO => 获取HTML中的资源依赖声明 })}
取得するデータはビニール オブジェクトであり、contents 属性はファイルのコンテンツです。 Buffer または It is String であり、文字列の内容は toStraing() を通じて取得できます。
すべての依存関係宣言には InlineResource キーワードが含まれています。簡単な方法は、正規表現を使用して HTML 内のリソース依存関係を見つけて置換することです。
html.replace(/<!--InlineResource:(.*?)-->/g, function (expr, fileRegexpStr){ // fileRegexp是用以匹配依赖资源的正则字符串})
この時点で、リソースの依存関係の配置が完了しました。次のステップは、置換用の依存リソースを取得することです。
ステップ 1 で定義した getResources メソッドを通じて必要なリソース ファイルを取得します。
module.exports = function (resourcesStream) { // step 1: ✔︎ // step 2: ✔ return mapStream(function (data, cb) { // step 3: ✔ getResources(function (list) { html.replace(depRegexp, function (expr, fileRegexpStr) { var fileRegexp = new RegExp(fileRegexpStr) // step 4: TODO => 获取匹配的依赖 }) }) })}
getResources は非同期メソッドであるため、置換処理ロジックは getResources のコールバック メソッドでラップする必要があります。
依存関係宣言の正規表現に従って、リソース リストを 1 つずつ照合します。
function matchingDependences(list, regexp) { var deps = [] list.forEach(function (file) { var fpath = file.path if (fileRegexp.test(fpath)) { deps.push(fpath) } }) return deps}
これは最後のステップです。リソースを HTML タグに変換し、HTML に挿入します
module.exports = function (resourcesStream) { // step 1: ✔︎ // step 2: ✔ return mapStream(function (data, cb) { // step 3: ✔ // step 4: ✔ // ... html.replace(depRegexp, function (expr, fileRegexpStr) { var deps = matchingDependences(list, fileRegexpStr) // step 5: 文件对象转换为HTML标签 }) })}
接下来的定义一个transform方法,用于将路径列表转换为HTML的资源标签列表,其中引入了 path模块用于解析获取文件路径的一些信息,该模块是node内置模块。
var path = require('path') function transform(deps) { return deps.map(function (dep) { var ext = path.extname(dep) switch (ext) { case 'js': '<script>' + dep + '</script>' break case 'css': return '<link rel="stylesheet" href="' + dep + '">' break } return '' }).join('')}
最终,我们将标签列表拼接为一个字符串来HTML中的依赖声明(注入):
html = html.replace(depRegexp, function (expr, fileRegexpStr) { var deps = matchingDependences(list, fileRegexpStr) // step 5: 文件对象转换为HTML标签 return transform(deps)})// html文件对象data.contents = new Buffer(html)// 把修改后的文件对象放回HTML流中cb(null, data)
到此也就完整地实现了一个拥有基本注入功能的插件~~~~~~
通过上面实现的示例步骤,可以清楚了解到gulp插件的工作原理。 但要做一个易用/可定制性高的插件,我们还要继续完善一下,例如:
在依赖声明中支持 inline 声明,用以将资源内容内联到HTML中,例如:
<!--InjectResources:*\.js$??inline-->
支持命名空间,用于往同一个资源流中使用多次资源注入的区分,例如:
gulp.src('index.html') .pipe( InjectResources(gulp.src('asserts/*.js'), { name: 'asserts'}) ) .pipe( InjectResources(gulp.src('components/*.js'), { name: 'components'}) ) ...