blog

数千行のSDKコードを最適化する方法

最近、プラグインモードと一括インポート機能の使用を共有するために、xgplayerのソースコードを見始め、SDKファイルの最適化コードの数千行のアプリケーションから引き出すことができます。 ソースコー...

Apr 21, 2020 · 5 min. read
シェア

最近、ソースコードを見て、その中のプラグインモードとバルクインポート関数の使用を共有し始めました。

I. どこから始めるソースコード

II プラグインモデルの実装

基本的な構成は以下の通り:

class Player { constructor() { // コンストラクタでプラグインを呼び出す this.pluginsCall() } // プラグインの呼び出し方法 pluginsCall () { let self = this if (Player.plugins) { // プラグインの実行をトラバースする Object.keys(Player.plugins).forEach(name => { let descriptor = Player.plugins[name] descriptor.call(this, this) } } }) } } // プラグインメソッドを静的にマウントする static install (name, descriptor) { if (!Player.plugins) { Player.plugins = {} } if (!Player.plugins[name]) { Player.plugins[name] = descriptor } } }

より良い設計ポイントは、プラグインをマウントするクラスの静的メソッドを提供し、次にプラグインを実行するコンストラクタを提供することです。これにより、参照元はカスタムプラグインをマウントできるインスタンスを作成し、インスタンスの作成時にプラグインを実行できます。

ソースコード内の20ほどのプラグインは、以下のような構造でcontrolsフォルダの下に統一されています:

├── cssFullscreen.js
...
i18n.js

すべてのプラグインは統一された構造を持ち、Playerを導入し、プラグインメソッドを宣言し、Player.installを呼び出してプラグインをインストールします:

import Player from '../player' let cssFullscreen = function () { } Player.install('cssFullscreen', cssFullscreen)

次のステップは、これらのプラグインコードを実行し、プレーヤーをエクスポートすることです:

import Player from './player' import * as Controls from './controls/*.js' export default Player

import * as Controls from './controls/*.js' ここでは、より巧妙な直接Playerをエクスポートされませんが、少し転送でこのファイルの使用は、時間の転送は、コードのこの行は、バッチすべてのコントロールフォルダプラグインと実行をヒットされ、一見この構文を見ていない、私は、バベルローダのデバッグを介して、処理を行うには、どのプロセスを知らないことを発見したバベルがされた後babel-plugin-bulk-import処理された後、ケースを解決するためにバベルの設定を見て、プラグインです。

つの babel-plugin-bulk-import

xgplayerbabelプラグインで、モジュールの一括インポートのためのglob 構文の使用をサポートしています。

Test case:

.
ケース
| サブフォルダ
| | ケース3.js // module.exports = { case: 999 };
| ケース1.js // module.exports = { case: 1 };
| ケース2.js // module.exports = { case: 2 };
| ケース3.js // module.exports = { case: require('./subfolder/case3') };
└── src
 インデックス.js

Example#1

import * as all from './case/**/*.js';

となります。

all = {
 case: { 
 case1: { case: 1 },
 case2: { case: 2 },
 case3: { case: { case: 999 } },
 subfolder: { case3: { case: 999 } } 
 } 
}

Example #2

import * as all from 'lodash/{*,**/*}.js';

となります。

all = {
 node_modules : {
 lodash: {
 LODASH_MODULE1: ITS_EXPORT_CONTENTS
 LODASH_MODULE2: ITS_EXPORT_CONTENTS
 ...
 }
 }
}

実装の原理

バベルプラグインを記述する方法は、その後説明する記事を開くことができ、ここでは最初の一般的なアイデアを達成するためにプラグインを見て、基本的にはglob構文に一致することであり、ファイルを取得するglobを使用して、ロジックの導入を書き換えます。バベルローダでは、次のようにバベルの後のコードを見てください:

"'use strict';
Object.defineProperty(exports, "__esModule", {
 value: true
});
var _cssFullscreen = require('./controls/cssFullscreen.js');
var _cssFullscreen2 = _interopRequireDefault(_cssFullscreen);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var Controls = {};
/**
@param v インポートの全体像
@param p インポートされたモジュールへのパスは、オブジェクト全体の属性として使用される。
@param a 最終的なモジュールのエクスポート
**/
function _buildTree(v, p, a) {
 var o = v;
 p.map(function (_, i) {
 o[_] = i == p.length - 1 ? a : o[_] || {};
 o = o[_];
 });
}
_buildTree(Controls, ['controls', 'cssFullscreen'], _cssFullscreen2.default);

実際、xgplayerのプラグインにはエクスポートされたコンテンツはありません。

アプリケーションの4つのまとめ

上記のプラグインモードの設計とバッチインポート機能により、開発においてSDKの単一ファイルが大きすぎるという問題を解決できるのではないかと思いつきました。

class SDK { constructor() { } method1() { } ... method99() { } } export default SDK

バッチインポートによる改善後の状況は以下の通りです:

SDK.js
インデックス.js
メソッド
│ ├── method1.js
...
│ └── method99.js

SDK.jsにあります。

export default class SDK { constructor() { } }

methodx.js.

import SDK from '../SDK'; SDK.prototype.methodx = function() { console.log('methodx'); }

index.jsにあります。

import SDK from './SDK'; import * as methods from './methods/*.js' export default SDK;

デモはこちら:

実際、SDKだけでなく、インポートルーティング、vueximportサブモジュール、各Reducerをインポートする際のcombineReducersのreduxなど、手作業で多くのインポートを必要とする場所はすべて最適化できます。

Read next

異形のES6エッセイ

ES6の珍しい、しかし便利な新効果だと思うものを記録してください!パッチワークパッチワークパッチワークパッチワーク言葉の断片!知らせろ!

Apr 21, 2020 · 6 min read