長い間フロントエンドにいなかった小さな開発者として、私はそれについて話さなければなりませんwebpack
。私が最初にウェブパックに連絡し始めたとき、最初の反応は何でしたか(⊙_⊙)?なぜそれはとても複雑で、とても難しいと感じます、それを忘れてください!時間は良いことです。正しい前端工程化
実践と理解が徐々に深まり、ウェブパックとの接触が増えるにつれて、彼はついに彼に納得し、「webpack yyds(永远滴神)!
」と叫ばざるを得なくなりました。
去年の半ばにウェブパックについての記事を書きたかったのですが、いろいろな理由で遅れました(主にウェブパックを十分に理解していないと感じ、傲慢に書くことを敢えてしませんでした)。ウェブパックに触れて、いくつかの「新年の商品」を整理し、困っているxdmと共有してください!xdm···の監督の下、フォローアップでいくつかの[Webpack]記事を書き続けます。
ガイド
この記事では、主にプラグインの実装によるcdn优化
プラグイン開発の特定のプロセスをCdnPluginInject
紹介します。真ん中は、プラグインの使用、プロジェクトでのWebpackプラグインの構成、およびWebpack関連のナレッジポイントの説明を含みます。全文は約2800語以上で、5〜10分かかると予想されます。xdmが読んだ後、学び、考え、出力できることを願っています。webpack
plugin
html-webpack-plugin
vue/cli3+
注:この記事の例は、vue/cli3+
プロジェクトの展開に基づいています。
1.CDNの定期的な使用
index.html:
<head>
···
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/vuex/3.1.0/vuex.min.js"></script>
<script src="https://cdn.bootcss.com/vue-router/3.0.2/vue-router.min.js"></script>
···
</body>
vue.config.js:
module.exports = {
···
configureWebpack: {
···
externals: {
'vuex': 'Vuex',
'vue-router': 'VueRouter',
···
}
},
2.Webpackプラグインを開発します
webpackの公式ウェブサイトではこれを紹介しています。プラグインはサードパーティの開発者にwebpackエンジンの完全な機能を提供します。段階的なビルドコールバックを使用して、開発者は独自の動作をWebpackビルドプロセスに導入できます。プラグインの作成は、ローダーの作成よりも高度です。対応するフックを実装するには、webpackの基本的な内部機能のいくつかを理解する必要があるためです。
プラグインは次のもので構成されています。
- 名前付きJavaScript関数。
- プロトタイプで適用メソッドを定義します。
- タッチウェブパック独自のイベントフックを指定します。
- Webpack内のインスタンス固有のデータを操作します。
- 関数の実装後に、webpackによって提供されるコールバックを呼び出します。
// 一个 JavaScript class class MyExampleWebpackPlugin { // 将 `apply` 定义为其原型方法,此方法以 compiler 作为参数 apply(compiler) { // 指定要附加到的事件钩子函数 compiler.hooks.emit.tapAsync( 'MyExampleWebpackPlugin', (compilation, callback) => { console.log('This is an example plugin!'); console.log('Here’s the `compilation` object which represents a single build of assets:', compilation); // 使用 webpack 提供的 plugin API 操作构建结果 compilation.addModule(/* ... */); callback(); } ); } }
3、CDN最適化プラグインの実装
アイデア:
- 1、名前の作成
JavaScript
機能(利用ES6
のclass
実現を)。 - 2、それはプロトタイプ
apply
メソッドで定義されています。 - 3. Webpack自体にアクセスするイベントフックを指定します(
compilation
フックはここでタッチされます:コンパイルが作成された後、プラグインが実行されます)。 - 図4に示すように、フックの動作の場合には
index.html
(TOに挿入中央)。cdn
script标签
index.html
- 5.
apply
メソッドが実行される前にcdn的参数
それwebpack
を入れてください外部扩展externals
; - 6.関数の実装後に
webpack
提供される呼び出しcallback
。
実装手順:
1、名前付きを作成しますJavaScript
(実現の機能ES6
を使用してclass
)
クラスを作成しcdnPluginInject
、渡されたパラメーターを受け取るクラスのコンストラクターを追加します。ここでは、受け取ったパラメーターの形式を次のように定義します。
modules:[
{
name: "xxx", //cdn包的名字
var: "xxx", //cdn引入库在项目中使用时的变量名
path: "http://cdn.url/xxx.js" //cdn的url链接地址
},
···
]
定義クラスの変数は、modules
渡されたcdn参数
処理結果を受け取ります。
class CdnPluginInject {
constructor({
modules,
}) {
// 如果是数组,将this.modules变换成对象形式
this.modules = Array.isArray(modules) ? { ["defaultCdnModuleKey"]: modules } : modules;
}
···
}
module.exports = CdnPluginInject;
2、それはプロトタイプapply
メソッドで定義されています
プラグインは、
apply
インスタンス化されたコンストラクターです(プロトタイプオブジェクトにはこのコンストラクターメソッドがあります)。apply
プラグをインストールするこの方法は、一度webpackコンパイラと呼ばれます。apply
このメソッドは、webpackコンパイラオブジェクトへの参照を受け取ることができるため、コールバック関数でコンパイラオブジェクトにアクセスできます。
cdnPluginInject.js
コードは次のように表示されます。
class CdnPluginInject {
constructor({
modules,
}) {
// 如果是数组,将this.modules变换成对象形式
this.modules = Array.isArray(modules) ? { ["defaultCdnModuleKey"]: modules } : modules;
}
//webpack plugin开发的执行入口apply方法
apply(compiler) {
···
}
module.exports = CdnPluginInject;
3.Webpack自体に触れるイベントフックを指定します
ここでcompilation
フックに触れます。コンパイルが作成された後、プラグインが実行されます。
compilation
はいcompiler
、フック関数です。コンパイルにより、コンパイルプロセスの新しいインスタンスが作成されます。コンパイルインスタンスは問題访问所有模块和它们的依赖
ありません。これらのモジュールを取得したら、必要に応じて操作できます。
class CdnPluginInject {
constructor({
modules,
}) {
// 如果是数组,将this.modules变换成对象形式
this.modules = Array.isArray(modules) ? { ["defaultCdnModuleKey"]: modules } : modules;
}
//webpack plugin开发的执行入口apply方法
apply(compiler) {
//获取webpack的输出配置对象
const { output } = compiler.options;
//处理output.publicPath, 决定最终资源相对于引用它的html文件的相对位置
output.publicPath = output.publicPath || "/";
if (output.publicPath.slice(-1) !== "/") {
output.publicPath += "/";
}
//触发compilation钩子函数
compiler.hooks.compilation.tap("CdnPluginInject", compilation => {
···
}
}
module.exports = CdnPluginInject;
4.フックイベントで操作しますindex.html
このステップでは、主に達成すべきであるに挿入してcdn
script标签
index.html
、それを達成するためにどのように?vueプロジェクトでは、webpackは実際にhtml-webpack-pluginを.html
使用してパッケージ化時にファイルを生成するため、ここでhtml-webpack-plugin
htmlファイルを操作してcdnスクリプトタグを挿入することもできます。
// 4.1 引入html-webpack-plugin依赖
const HtmlWebpackPlugin = require("html-webpack-plugin");
class CdnPluginInject {
constructor({
modules,
}) {
// 如果是数组,将this.modules变换成对象形式
this.modules = Array.isArray(modules) ? { ["defaultCdnModuleKey"]: modules } : modules;
}
//webpack plugin开发的执行入口apply方法
apply(compiler) {
//获取webpack的输出配置对象
const { output } = compiler.options;
//处理output.publicPath, 决定最终资源相对于引用它的html文件的相对位置
output.publicPath = output.publicPath || "/";
if (output.publicPath.slice(-1) !== "/") {
output.publicPath += "/";
}
//触发compilation钩子函数
compiler.hooks.compilation.tap("CdnPluginInject", compilation => {
// 4.2 html-webpack-plugin中的hooks函数,当在资源生成之前异步执行
HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration
.tapAsync("CdnPluginInject", (data, callback) => { // 注册异步钩子
//获取插件中的cdnModule属性(此处为undefined,因为没有cdnModule属性)
const moduleId = data.plugin.options.cdnModule;
// 只要不是false(禁止)就行
if (moduleId !== false) {
// 4.3得到所有的cdn配置项
let modules = this.modules[
moduleId || Reflect.ownKeys(this.modules)[0]
];
if (modules) {
// 4.4 整合已有的js引用和cdn引用
data.assets.js = modules
.filter(m => !!m.path)
.map(m => {
return m.path;
})
.concat(data.assets.js);
// 4.5 整合已有的css引用和cdn引用
data.assets.css = modules
.filter(m => !!m.style)
.map(m => {
return m.style;
})
.concat(data.assets.css);
}
}
// 4.6 返回callback函数
callback(null, data);
});
}
}
module.exports = CdnPluginInject;
次に、上記の実現を段階的に分析します。
- 4.1.html-webpack-pluginの依存関係を導入します。言うまでもありません。
- 4.2。呼び出し
html-webpack-plugin
のhooks
関数は、html-webpack-plugin
リソースが生成される前に非同期で実行されます。これはhtml-webpack-plugin
、開発html-webpack-plugin
者がプラグインを呼び出すさまざまな段階でさまざまな操作を埋め込むために、開発中にプラグインに多くのフック関数を構築したことを心から自慢している著者です。ので、ここでは使用することができます動作するHTMLのペアを。html-webpack-plugin
beforeAssetTagGeneration
- 4.3。
beforeAssetTagGeneration
必要性がでCDNによってインポートされることをすべての構成データを取得します。 - 4.4。既存のjs参照とcdn参照を統合します。ステージで生成された(そして最終的にindex.htmlに挿入された)すべてのリンク/パスを
data.assets.js
取得compilation
しjs资源
、構成が必要なものをcdn的path数据(cdn的url)
マージできます。 - 4.5。既存のcss参照とcdn参照を統合します。ステージで生成された(そして最終的にindex.htmlに挿入された)すべてのリンク/パスを
data.assets.css
取得compilation
しcss资源
、構成が必要なcssタイプをcdn的path数据(cdn的url)
マージできます。 - 4.6。コールバック関数を返します。目的は
webpack
、操作が完了し、次のステップに進むことができることを通知することです。
5、設定webpack
外部扩展externals
apply
メソッドを実行 する前に、完了する必要のあるもう1つのステップがあります。それをcdn的参数
構成外部扩展externals
しますcompiler.options.externals
。webpackでexternals属性を直接取得し、操作後にcdn構成でデータを構成できます。
6 、callback
;
コールバックを返して、WebpackCdnPluginInject
プラグインが完了したことを通知します。
// 4.1 引入html-webpack-plugin依赖
const HtmlWebpackPlugin = require("html-webpack-plugin");
class CdnPluginInject {
constructor({
modules,
}) {
// 如果是数组,将this.modules变换成对象形式
this.modules = Array.isArray(modules) ? { ["defaultCdnModuleKey"]: modules } : modules;
}
//webpack plugin开发的执行入口apply方法
apply(compiler) {
//获取webpack的输出配置对象
const { output } = compiler.options;
//处理output.publicPath, 决定最终资源相对于引用它的html文件的相对位置
output.publicPath = output.publicPath || "/";
if (output.publicPath.slice(-1) !== "/") {
output.publicPath += "/";
}
//触发compilation钩子函数
compiler.hooks.compilation.tap("CdnPluginInject", compilation => {
// 4.2 html-webpack-plugin中的hooks函数,当在资源生成之前异步执行
HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration
.tapAsync("CdnPluginInject", (data, callback) => { // 注册异步钩子
//获取插件中的cdnModule属性(此处为undefined,因为没有cdnModule属性)
const moduleId = data.plugin.options.cdnModule;
// 只要不是false(禁止)就行
if (moduleId !== false) {
// 4.3得到所有的cdn配置项
let modules = this.modules[
moduleId || Reflect.ownKeys(this.modules)[0]
];
if (modules) {
// 4.4 整合已有的js引用和cdn引用
data.assets.js = modules
.filter(m => !!m.path)
.map(m => {
return m.path;
})
.concat(data.assets.js);
// 4.5 整合已有的css引用和cdn引用
data.assets.css = modules
.filter(m => !!m.style)
.map(m => {
return m.style;
})
.concat(data.assets.css);
}
}
// 4.6 返回callback函数
callback(null, data);
});
// 5.1 获取externals
const externals = compiler.options.externals || {};
// 5.2 cdn配置数据添加到externals
Reflect.ownKeys(this.modules).forEach(key => {
const mods = this.modules[key];
mods
.forEach(p => {
externals[p.name] = p.var || p.name; //var为项目中的使用命名
});
});
// 5.3 externals赋值
compiler.options.externals = externals; //配置externals
// 6 返回callback
callback();
}
}
module.exports = CdnPluginInject;
この時点で、完全なWebpackプラグインCdnPluginInject
が開発されました。次に試してみましょう。
4つのcdn最適化プラグインの使用
vueプロジェクトのvue.config.js
ファイルで紹介して使用しますCdnPluginInject
:
cdn構成ファイルCdnConfig.js:
/*
* 配置的cdn
* @name: 第三方库的名字
* @var: 第三方库在项目中的变量名
* @path: 第三方库的cdn链接
*/
module.exports = [
{
name: "moment",
var: "moment",
path: "https://cdn.bootcdn.net/ajax/libs/moment.js/2.27.0/moment.min.js"
},
···
];
configureWebpackで構成します。
const CdnPluginInject = require("./CdnPluginInject");
const cdnConfig = require("./CdnConfig");
module.exports = {
···
configureWebpack: config => {
//只有是生产山上线打包才使用cdn配置
if(process.env.NODE.ENV =='production'){
config.plugins.push(
new CdnPluginInject({
modules: CdnConfig
})
)
}
}
···
}
chainWebpackでの構成:
const CdnPluginInject = require("./CdnPluginInject");
const cdnConfig = require("./CdnConfig");
module.exports = {
···
chainWebpack: config => {
//只有是生产山上线打包才使用cdn配置
if(process.env.NODE.ENV =='production'){
config.plugin("cdn").use(
new CdnPluginInject({
modules: CdnConfig
})
)
}
}
···
}
を使用してCdnPluginInject
:
- 1.構成を通じてCDN最適化の管理と保守を実現します。
- 2.さまざまな環境のCDN構成の最適化を実現します(開発環境はローカルインストールの依存関係を直接使用してデバッグし、実稼働環境はCDNモードに適応してロードを最適化します)。
V.まとめ
それを読んだ後webpack
、大物からいくつかの疑いがあるに違いありません、このプラグインはwebpack-cdn-pluginの物乞いバージョンではありません!プロジェクトが実際に変更する必要のある模倣バージョンと組み合わせてCdnPluginInject
、webpack-cdn-plugin
ソースコードから学ぶだけですwebpack-cdn-plugin
。cdnリンクの生成をカプセル化するのと比較して、cdnリンクCdnPluginInject
を直接構成することで、cdn構成を選択するのが簡単になります。詳細を知りたい場合は、xdmwebpack-cdn-plugin
のソースコードを参照してください。作成者が継続的に繰り返し更新した後、より構成可能なパラメーターとより強力な機能が提供されます(ここでも)。
重点:整理不易,觉得还可以的xdm记得 一键三连 哟!