:この記事はで再現された猿2048ウェブサイト➥ https://www.mk2048.com/blog/blog.php?id=hkc0chhjaa
この記事で
- プラグインおよび小型パッケージ化プラグインの開発を開発する方法のWebPACK
- 開発プロセスで発生した問題とどのように解決するために
- どのようなミニプログラム-WebPACKのローダを行うことができます
開発WebPACKのプラグ
私は、学生が見てきた、プラグインで働いていたと考えているプラグインの書き方理由だけで、このツールをリリースしたミニプログラム-WebPACKのローダ4の開発WebPACKの、または類似の物品を、その方法は、以下のいくつかを読んで私は、記事を読んでドキュメント。
あなたが文書を読めば、私はあなたが知っている必要があります信じています:
- 各プラグインはWebPACKのエンジンが実行したいコードを実行する方法を適用しなければなりません。
- 二つの重要なオブジェクトおよびコンパイラのコンパイルは、あなたが読むことができる特定のイベントフック、上記(呼び出すときに、この手順を実行するにはWebPACKの)イベントフックをバインドすることができますコンパイラフック。
- モジュールとチャンクとの関係、私たちはそれぞれのファイルを理解することができ、モジュールを持つことになりますし、チャンクは、モジュールの複数で構成されています。
- WebPACKのパッケージ全体のプロセス、それらのイベント
- シンプルなローダーの書き方
先に進むことができないと感じた場合、私はアプレットをパックするミニプログラム-WebPACKのローダを開発し、改善する方法をステップバイステップで表示され続けることがあります。
アプレットは、すべてのページのパスのapp.jsonファイルを持っている、あなたの最初の必要性の固定ルーチンを持っており、各ページには4つのファイルがあります:.jsファイル、.json、.wxml、.wxssを。だから私は、エントリアプレットページが何であるかによって知るために、WebPACKの実行は、プラグインを適用すると、WebPACKのエントリとしてapp.json注文します。おそらくフローチャートのようなもの、小さなプラグインパッケージはほぼので、完全な。
これは、二つのプラグインMultiEntryPlugin、SingleEntryPluginを使用しています。なぜそれを行いますか?WebPACKの数が設定されているので(ここでは、エントリがエントリ内だけのWebPACKの構成ではありません、インポート()、エントリが生成されますrequire.ensure())生成されたファイルを決定するためにあなたのエントリに基づいて、我々はすべてのページのJSを配置する必要はありませんファイルにパッケージ化、あなたは新しいエントリモジュールを生成するためにSingleEntryPluginを使用する必要があります。これらの静的リソースをして、我々はMultiEntryPluginプラグイン入力モジュールの依存関係としてこれらの文書を処理するために使用することができ、ローダーの静的ファイルローダへの構成ファイル出力。擬似コードは次のよう:
const MultiEntryPlugin = require('webpack/lib/MultiEntryPlugin');
const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin');
class MiniPlugin {
apply (compiler) {
let options = compiler.options
let context = compiler.rootContext
let entry = options.entry
let files = loadFiles(entry)
let scripts = files.filter(file => /\.js$/.test(file))
let assets = files.filter(file => !/\.js$/.test(file))
new MultiEntryPlugin(context, assets, '__assets__').apply(compiler)
scripts.forEach((file => {
let fileName = relative(context, file).replace(extname(file), '');
new SingleEntryPlugin(context, file, fileName).apply(compiler);
})
}
}
あなたは上記のように、あなたは最終的にはxxx.js(MultiEntryPlugin名を使用した場合に記入)、main.jsのよりになることを見つけることを行う場合はもちろん、構成エントリを対応するmain.jsが生成されたファイル、xxx.jsですMultiEntryPluginが発生しました。これらのファイルは、私たちが必要とするものではありませんので、彼を除去する必要があります。あなたはおなじみのWebPACKの文書であれば、我々は多くの場所を持っているあなたは、コンパイラなど、最終文書のうち、パッケージを変更できるイベント、達成することができoptimizeChunks関連イベントのコンパイルを発します。その本質は、compilation.assetsオブジェクトを変更することです。
コンテンツを処理するためのイベントの使用上のミニプログラム・WebPACKのローダでは、このような不要な出力を発します。このようなおそらくプロセス:
小型パッケージもちろんそう単純ではない、wxml、wxss、WXSとコンポーネントの自己参照定義をサポートしなければならなかったので、我々はローダーを完了する必要があり、この時間は、ローダが行われる必要があることは非常に簡単です - 依存するファイルを解決するために、などSRCのインポート・コンポーネントを解決する必要があり.wxml、SRCのWXSは、.wxssは、WXS年代が必要@インポートを解析し、そして最後の方法は、ローダでのLoadModuleを使用することができます追加する必要があります。エントリー・ステップを追加するときに、直接アクセスのカスタムアセンブリを開始、ローダーを完了する必要はありません。このタイムマップ:
また、問題はないだろうが、開発の経験が比較的貧弱である、などのカスタムコンポーネント、ページ、WebPACKのを追加することを認識していないので、ページ内の.json変更は新しいカスタムでないときに確認する必要がありますコンポーネントまたはページを追加します。JSカスタムコンポーネントを追加するaddModuleの道ではないので、自己JS-定義されたコンポーネントは別の入り口を提出しなければならないので、この時間は、問題が発生しました。それは、ローダではないので、(実行前にプラグインローダーので、プラグインローダーと通信を確立することが可能である)プラグインにファイルを試してみてください。シンプルで粗製の方法:
// loader.js
class MiniLoader {}
module.exports = function (content) {
new MiniLoader(this, content)
}
module.exports.$applyPluginInstance = function (plugin) {
MiniLoader.prototype.$plugin = plugin
}
// plugin.js
const loader = require('./loader')
class MiniPlugin {
apply (compiler) {
loader.$applyPluginInstance(this);
}
}
しかし.... プラグインファイルが到達し、その後、SingleEntryPluginを使用しますが、とき、あなたは何の効果も見つけませんされています。コンパイラはWebPACKの追加された新しいモジュールを認識していない行った後なので、それは、あなたがこの文書に基づいて推測する必要がある場合、WebPACKの新しいモジュールを認識さ取得する方法を、文書イベントに応じて、キーワード検索を行う、役に立ちません完成コンパイルneedAdditionalPassイベントがフックを呼び出しますコンパイル時に見つけることができます:
this.emitAssets(compilation, err => {
if (err) return finalCallback(err);
if (compilation.hooks.needAdditionalPass.call()) {
compilation.needAdditionalPass = true;
const stats = new Stats(compilation);
stats.startTime = startTime;
stats.endTime = Date.now();
this.hooks.done.callAsync(stats, err => {
if (err) return finalCallback(err);
this.hooks.additionalPass.callAsync(err => {
if (err) return finalCallback(err);
this.compile(onCompiled);
});
});
return;
}
this.emitRecords(err => {
if (err) return finalCallback(err);
const stats = new Stats(compilation);
stats.startTime = startTime;
stats.endTime = Date.now();
this.hooks.done.callAsync(stats, err => {
if (err) return finalCallback(err);
return finalCallback(null, stats);
});
});
});
あなたがイベントにフックを真の値を返す場合は、コンパイラadditionalPassのWebPACKのイベントフックを呼び出すことができ、ここにファイルを追加しようと、それは本当に可能です。この時間は、マップは、このになっています:
あなたは所望の効果を達成するための多くの方法があることがわかります後に起動したときにもちろん、このような良いsplitchunkを作る方法を下請け、などの小型パッケージ、いくつかの異なった場所は、、、LAで息切れません。
あなたは時に各コールバック、彼らとのWebPACKがはるかに簡単に何をすべきか知っているときプラグイン開発ここでは、ほぼ、一般的には、WebPACKのは、補正のパターンを変えています。問題のいくつかは、開発プロセスで発生したためもちろん、私は、知りません。
問題が発生しました
1.解決の別名をサポートするために、どのように、アプレットコードをnode_modules?
それはツールであるので、当然のことながら、より多くのことを行う必要があり、このように複雑で、サポートされている場合解決エイリアスのような小さなプログラムがあり、プロジェクトはそれが簡単に維持するために作ることができ、そしておそらくあなたは、これが最も基本的な機能は行っておりませんWebPACKのではないことを言うだろうnode_modulesもちろん、任意の文書でエイリアスを使用することを望んでいる、node_modulesはちょうどJS以上をサポートしています。WebPACKのリゾルブ4は、もはや同期でサポートされているのでもちろん、これは物事が複雑になることを意味し、すべての最初のファイルパスを取得することです、それは非同期である必要があります。第二はnode_modulesすることはできませんディレクトリアプレットの名前で、我々は、現在のプロジェクトディレクトリへの相対パス、または相対的なパッケージング出力ではなく、相対を計算するルールを必要としています。
2.複数の小さなプロジェクトのプログラムをマージ
子供の頃のプログラムからの賞賛が懸念されてあり、マイクロモール版、製品版と公開版、最も基本的な機能があり、ビジネスはもちろん、アプレットごとに一回、同じ開発することはできませんので、小さな複数のマージと、このツールもちろん、プログラムをする必要があります。このような少しより合併し、ための小さなプログラムの数はページが正しいことをマージするだけでなく、同じパスを確保するためにすることを確保する必要性から、node_modules複合体からファイルを取ります。
ディレクトリパッケージファイルパスの絶対パスを計算し、その後、ファイルapp.json入口ディレクトリのパスに応じて、最終的な出力パスを計算するための基準として、SRCディレクトリのWebPACK rootContextディレクトリに両方これら二つの問題に最終溶液。
exports.getDistPath = (compilerContext, entryContexts) => {
/**
* webpack 以 config 所在目录的 src 为打包入口
* 所以可以根据该目录追溯源文件地址
*/
return (path) => {
let fullPath = compilerContext
let npmReg = /node_modules/g
let pDirReg = /^[_|\.\.]\//g
if (isAbsolute(path)) {
fullPath = path
} else {
// 相对路径:webpack 最后生成的路径,打包入口外的文件都以 '_' 表示上级目录
while (pDirReg.test(path)) {
path = path.substr(pDirReg.lastIndex)
fullPath = join(fullPath, '../')
}
if (fullPath !== compilerContext) {
fullPath = join(fullPath, path)
}
}
// 根据 entry 中定义的 json 文件目录获取打包后所在目录,如果不能获取就返回原路径
let contextReg = new RegExp(entryContexts.join('|'), 'g')
if (fullPath !== compilerContext && contextReg.exec(fullPath)) {
path = fullPath.substr(contextReg.lastIndex + 1)
console.assert(!npmReg.test(path), `文件${path}路径错误:不应该还包含 node_modules`)
}
/**
* 如果有 node_modules 字符串,则去模块名称
* 如果 app.json 在 node_modules 中,那 path 不应该包含 node_modules
*/
if (npmReg.test(path)) {
path = path.substr(npmReg.lastIndex + 1)
}
return path
}
}
別々のパッケージ化されたコンテンツに依存するサブカプセル化にパッケージを処理する方法3
この問題に対する解決策はoptimizeChunks事象によるものである、モジュールの各チャンクに依存してエントリファイルのこのチャンクを追加し、その後のテスト構成splitChunkに依存しているモジュールの数をチェックします。一つだけの場合、およびキルトパッケージ、サブパッケージにパッケージに依存しています。
失敗した1つのファイルをサポートし4.webpack
これは、それはそう簡単ではないと思われる1つのファイルをサポートするためのWebPACKを使用しようと問題ではありません。
- 4つのファイルにファイルの後に1つのファイルを分割し、ファイルを作成するためにemitFileとaddDependencyを使用することができますが、ローダが作成され実行されません。
- なぜなら、ファイルシステムのLoadModuleのを使用してファイルが存在しない文句を言うだろう
最後に書かれました
最後に、当然のことながら、ミニプログラム・WebPACKのローダが行うことができます説明するものです。
このツールは、主に次の問題に対処しています。
- アプレットは、NPMにサポートされていません。
- ディレクトリのネストが深すぎ、難しいパス管理
- 古いプロジェクトはコストがかかりすぎる、新しいツールを使用したい、大きすぎます
- 従来の最適化のヒントに大小物
繰り返します
- あなたは直接ダウンロードするためにNPMを使用することができますzanui-weapp
- あなたは「../../../../../xxx」にさよならを言うことができます
- あなたは互換性のない心配しないで、新しい機能を書くためにmpVue、里芋を使用することができます
:ドキュメントのアドレス残して最後に、最後のミニプログラム-WebPACKの-ローダーを