「まず彼を否定し、次に彼を憎み、そして彼なしでは生きられない」
Artyom Kurbatovのレポート「BEM:master class」から
BEM方法論はかなり前から存在しており、Google、EPAM Systems、BBC、Alfa Bankで採用されています。 ただし、通常の中間レベルの開発者およびプロジェクトマネージャーの間では依然として懸念が生じます。
一部の向こう見ずな人にとって、BEMの研究は、より予測可能な結果を得るためにCSSの限界を超えていません。 BEMはレイアウトをはるかに超えていますが、「BEMを知っていますか?」という質問を聞くことができます。「もちろん、これはクラスで下線を引くことです。」
BEMのアイデアがこれに近い場合、新卒の卒業生を雇用する際に雇用主の言葉で答えます。「以前BEMについて聞いたことを忘れてください」。 BEM方法論は、ほとんどが何も知らないのと同じくらい興味深いものです。 BEMの美しさを理解するには、BEMが提供するすべてのテクノロジー、ライブラリ、フレームワーク、およびツールのアイデアが必要です。 それらを研究し、外国人であり続け、大人が何に対処してきたのか疑問に思う子供です。
目次
私にとってのBEMとは何ですか?
ガレージで閉じた大胆なオタクが別のスタートアップを発明した方法の話を聞いたことは間違いありません。 最初の成功により、彼らは投資を呼び込み、驚くべき製品で市場に参入することができました。 彼らはどのように成功し、どのようにしてピーク負荷に耐え、永続的なリファクタリングで行き詰まることはありませんでしたか? 通常ではなく、どのように必要ですか?
BEMは、スタートアップのライフハックです。 他の多くのフレームワークやテクノロジーと比較して、BEMの使用を開始するには多少の努力が必要ですが、持続可能な拡張性を提供するアーキテクチャが得られます。 すべてのBEMテクノロジー、フレームワーク、およびライブラリには、最初に宣言的アプローチの原則が組み込まれています。 そして、これは彼らを一見して理解しにくくし、最終的に愛するものです。
この記事を読んだ後は、BEM Zenを理解することはできませんが、CSSだけでなく本格的な動的BEMプロジェクトを作成する方法を学んだ大人に間違いなく答えることができます。 また、明日、アプリケーションが1日あたり+10 Kユーザーという運命に陥った場合、落ち着いてください。このイベントを祝う時間があるでしょう。
今日は、動的なbem-expressプロジェクトの新しいテンプレートリポジトリについて説明します。これにより、BEMプロジェクトをワンクリックでデプロイできるだけでなく、プロジェクトを自動的に再構築し、ブラウザをリロードできます。 それに基づいて、動的アプリケーションを開発し、さまざまなBEMテクノロジーの相互作用プロセスを説明します。 「クラスで下線を引く」運命を回避するために、レイアウトとクライアント側のJavaScriptの問題を意識的に検討することはありません。
何を開発しますか?
ソーシャルサービス検索ロボット(略してSSSR)。リクエストに応じて、YouTubeからの最新のツイートやビデオを表示します。
以下を使用します。
- i-bem.jsフレームワーク 。
- bem-xjstテンプレートエンジン。
- DEPS依存関係を記述するための技術。
- Express.js ;
- YouTube Data API
- Twitter Search API 。
最初にインストールする必要があります:
重要! Windowsユーザーは、 Git Bashを追加でインストールする必要があります。
使用される表記
記事を明るくするために、少し描画します。
-ディレクトリ;
-ファイル;
-ディレクトリを作成します。
-ファイルを作成します。
-ファイルを編集します。
使用技術
BEMでは、テクノロジーをメインとセカンダリに分離することはありません。 セットがあり、アプリケーションの選択は個別に決定されます。
- BEMDECLは、BEMで宣言を記述するためのテクノロジーです。
- DEPSは、BEMで依存関係を記述するためのテクノロジーです。
- BEMTREE-データをBEMJSONに変換するテンプレートエンジン。
- BEMHTML -BEMJSONをHTMLに変換するテンプレートエンジン。
- i-bem.js -BEMのJavaScriptフレームワーク。
BEMJSON入力フォーマットの詳細をご覧ください。
それらを詳しく見てみましょう。
BEMDECL
ページのBEMエンティティのリストを定義します。
このようなBEMのリストは、 宣言と呼ばれます。 宣言の目的は、アセンブリに接続する順序と順序を決定することです。
宣言は、拡張子が.bemdecl.js
ファイルに記述されています。
例
exports.blocks = [ { name: 'page' }, { name: 'header' }, { name: 'body' }, { name: 'footer' } ];
ブロックの数が「覚えやすい」行を超えると、それらを正しい順序でリストするという問題が発生します。 したがって、彼らは通常、特定のブロックを宣言します。これは、中央の「エントリポイント」と見なされるべきです。
他のすべてのBEMエンティティは、 依存関係アセンブリに分類されます。
Deps
プロジェクトのファイル構造全体に広がり、宣言には反映されないBEMエンティティ間の依存関係を定義します。
依存関係は、拡張子が.deps.js
ファイル内のJavaScriptオブジェクトとして記述されます。
例
/* page header */ ({ block: 'page', shouldDeps: [ { block: 'header' } ] })
このテクノロジーの名前は英語の依存性に由来し、BEMエンティティをアセンブリに接続することを意味します。 BEMの学生は、テクノロジーの宣言的な性質を忘れることがあり、困惑します。テンプレートで説明されているブロックについて、そのスタイルとスクリプトが収集されないのはなぜですか。
覚えておいてください:何らかの種類のブロック(子ノード)を持つテンプレート( BEMHTMLまたはBEMTREE )を記述するとき、新しいHTML要素を追加するだけです。 このブロックのスタイルとスクリプトがアセンブリに入るためには、依存関係を記述する必要があります。
たとえば、 header
、 body
およびfooter
ブロックをアセンブリに追加するには、それらへの依存関係を記述する必要があります。
/* page header, body, footer */ ({ block: 'page', shouldDeps: [ 'header', 'body', 'footer' ] })
次の図は、依存関係ごとのビルドロジックを示しています。
index(DECL) # page | └──> page(DEPS) # page header, body, footer | ├──> header(DEPS) | | | └──> ... | ├──> body(DEPS) | | | └──> ... | └──> footer(DEPS) | └──> ...
ベントレー
bem-xjstテンプレートエンジンの一部であり、データをBEMJSONに変換します。
テンプレートは、拡張子.bemtree.js
ファイルにBEMJSON形式で記述されています。
テンプレートの入力と出力:
BEMHTML
これはbem-xjstテンプレートエンジンの一部であり、ページのBEMJSON記述をHTMLに変換します。
テンプレートは、拡張子が.bemhtml.js
ファイルに記述されています。
テンプレートの入力と出力:
i-bem.js
クライアント-BEM方法論の一部としてのWeb開発用のサイドJavaScriptフレームワーク 。
JavaScriptコードは、拡張子が.js
ファイルに記述されています。
許可:
- ブロック、要素、修飾子に関するWebインターフェイスを開発します。
- ブロックのロジックを宣言スタイルで-状態のセットとして記述します。
- JavaScriptコードとBEMHTMLテンプレートおよびCSSを簡単に統合
- ライブラリブロックの動作を柔軟に再定義します。
こんにちは、Worldアプリ
プログラマーには伝統があります。Hello、Worldアプリケーションを使用して、新しい言語またはフレームワークでプログラミングを開始してください。 アプリケーションは通常、「Hello、World」という単語を出力ストリームに書き込みます。これにより、アプリケーションが開始し、I / Oを実行することを示します。
作成して、目的のSSSRに展開します。
bem-expressテンプレートリポジトリのローカルコピーが必要です 。 Gitを使用して実行できます。
ご注意 OS XまたはLinuxのユーザーの場合、すべてのコマンドはターミナルで実行されます。 WindowsユーザーにはGit Bashが必要になります。 Git Bashが管理者として実行されていることを確認してください。
テンプレートリポジトリ
BEMのフレームワーク内で動的アプリケーションを開発する問題を解決するために、テンプレートリポジトリbem-expressが作成されました 。 必要な最小構成ファイルが含まれており、プロジェクトの構築、リンターのセットアップ、ライブラリの接続など、タスクのクラス全体を解決します。
メインのBEMライブラリはデフォルトで接続されています:
クイックスタート
Hello、Worldアプリケーションを作成するには:
bem-expressのクローン:
git clone https://github.com/bem/bem-express.git sssr-project
ご注意 この例では、
bem-express
バージョン2.00を使用します。
プロジェクトディレクトリに移動します。
cd sssr-project
ソースリポジトリのバージョン管理履歴を削除します。
rm -rf .git
独自のGitリポジトリを初期化します。
git init
依存関係をインストールします。
npm install
ご注意 npm依存関係をインストールするときに、ルートスーパーユーザー
root
使用しないでください。
プロジェクトをビルドし、サーバーを起動します。
npm run dev
ご注意 アセンブリはENBを担当します。
アプリケーションが起動すると、ターミナルにサーバーがポート3000で実行されているというメッセージが表示されます。
Server is listening on 3000
ます。
ご注意 ポート
3000
別のプログラムで使用されている場合は、再割り当てできます。 たとえば、8000
:
方法1.アプリケーションの起動時に値を変更します。
PORT=8000 npm run dev
方法server/config.js
デフォルト値を変更しserver/config.js
。
defaultPort: 8000,
コンピューター上で開始されました:
- サーバー-動的データの処理を担当します。
- nodemon- ファイル構造の変更を監視し、サーバーを再起動します。
- chokidar-
*.blocks/
ディレクトリファイルの変更を監視し、プロジェクト構造を再構築します。 - livereload-ブラウザのページを更新します。
ブラウザーを開き、 localhost:3000アドレスを入力します。
次のコンテンツを含むページが開きます。
Index page content footer content
ご注意 Windowsでアプリケーションを起動するときに、ファイアウォールから通知が表示される場合:
- [ パブリックネットワーク ]オプションをオフにします。
- オプションPrivate Networksを設定します。
- アクセスを許可します。
server/index.js
を開き、行app.get('/', function(req, res)
始まるコードで以下の変更(コメントを参照)を行います。
/** * GET- * @function * @param {object} req - . * @param {object} res - . */ app.get('/', function(req, res) { var hello = 'Hello'; // `hello` var world = 'World'; // `world` render(req, res, { view: 'page-index', title: 'Main page', meta: { description: 'Page description', og: { url: 'https://site.com', siteName: 'Site name' } }, hello: hello, // `hello` `this.data.hello` world: world // `world` `this.data.world` }) });
ファイル
common.blocks/page-index/page-index.bemtree.js
、その内容を次のものに置き換えます。
block('page-index').content()(function() { // `this` var data = this.data; // : `data.hello: 'Hello'`, `data.world: 'World'` return data.hello + ', ' + data.world; });
保存後、サーバーは自動的に再起動し、ページコンテンツが次のように変更されます。
Hello, World footer content
こんにちは、Worldアプリの準備ができました。
うまくいかなかった?
アプリケーションの作成中に問題が発生した場合は、 フォーラムで解決策を探してください 。 準備ができていない場合は、質問してください。
ソーシャルサービス検索ロボットアプリ
実際、SSSRアプリケーションを開発する段階に到達しました。 リクエストに応じて、アプリケーションはYouTubeからの最新のツイートとビデオを表示することを思い出させてください。
すぐに近い将来に実行されます-アプリケーションは次のようになります。

応募スキーム
ステップ1.リクエスト
ユーザーはサーバーにリクエストを送信します。
ステップ2.データの取得
アプリケーションは、受け取った要求に従ってTwitter Search APIおよびYouTube Data APIにデータを要求します。
ステップ3. BEMTREEテンプレート
アプリケーションは、受信したデータをBEMTREEテンプレートエンジンに渡します。BEMTREEテンプレートエンジンは、データをBEMJSONに変換します。
ステップ4. BEMHTMLテンプレート
アプリケーションは、BEMJSONをHTMLに変換するBEMHTMLテンプレートエンジンにBEMJSONを渡します。
ステップ5.結果をユーザーに送信する
アプリケーションは結果(HTMLページ)をユーザーに返します。
使用済みノードモジュール
Nodeの基本的な実装は可能な限りシンプルなままです。 すべての可能なコンポーネントをNodeに直接埋め込む代わりに、開発者は追加の機能を個別のモジュール(パッケージ)の形で提供します。
Nodeモジュールシステムは、相互作用するモジュールを作成するメカニズムであるCommonJSシステムをモデルにしています。 システムの中心は契約によって占められています。契約は開発者が実行する必要があります。そのため、開発者のモジュールは通常、他のモジュールと対話します。
npmパッケージマネージャーを使用してインストールされたすべてのパッケージは、 node_modules
ディレクトリにあります。
モジュールはrequire
コマンドを使用して接続されます。 パッケージがnpmを使用してインストールされている場合、パスを指定する必要はありません。 名前を示すだけで十分です。
var express = require('express');
独自のローカルモジュールを接続するときは、そのモジュールへのパスを指定する必要があります。
var someModule = require('./somefolder/somemodule');
モジュールの重要な機能は、Nodeと対話するように設計する必要があることです。 これを行うには、 module.exports
を使用してモジュールをエクスポートする必要があります。
module.exports = { // some module };
アプリケーションが機能するには、次のモジュールが必要です。
- エクスプレス -Webアプリケーションの構築に必要な機能のほとんどを提供します。
- パスポート -Node.jsアプリケーションにさまざまな認証戦略を提供します。
- passport-youtube-v3 -YoutubeアカウントとOAuth 2.0トークンを介してYoutubeで認証メカニズムを提供します。
- twitter -Twitter REST APIを操作するためのクライアントライブラリ。
- googleapis -Google REST APIを操作するためのクライアントライブラリ。
- moment-日付の解析、検証、フォーマット用のJavaScriptライブラリ。
1つのコマンドでインストールできます:
npm install express passport passport-youtube-v3 twitter googleapis moment --save
プロジェクト構造の準備
コードを書き始める前に、基礎となるHello、Worldアプリケーションの構造を少し変更しましょう。
変更点:
静的ファイルの変更
static
ディレクトリ
images
サブディレクトリを作成します。
- faviconを
images
サブディレクトリに移動します。
common.blocks
ディレクトリ
root/root.bemtree.js
編集しroot/root.bemtree.js
。
変更:
favicon: '/favicon.ico',
オン:
favicon: '/images/favicon.ico',
server
ディレクトリ
index.js
ファイルを編集します。
変更:
.use(favicon(path.join(staticFolder, 'favicon.ico')))
オン:
.use(favicon(path.join(staticFolder, '/images/favicon.ico')))
サーバーコードの変更
server
ディレクトリ
サブディレクトリを作成します。
-
controllers
-コントローラー; -
helpers
-ヘルパー; -
middleware
-middleware
モジュール。
-
将来のモジュール用に空の
JS
ファイルを作成します。
-
app.js
中間モジュールをマウントするためのモジュール(アプリケーションで使用可能にします); -
auth.js
-YouTube認証モジュール。 -
routes.js
-Web要求ルーティングモジュール。
-
app.js
ファイルに次のコードを追加します。
routes.js
ファイルに次のコードを追加します。
構成ファイルの拡張子を変更します。
config.js
>config.json
config.json
ファイルを編集します。
変更:
module.exports = { staticFolder: 'static', defaultPort: 3000, cacheTTL: 30000, sessionSecret: 'REPLACE_ME_WITH_RANDOM_STRING' };
オン:
{ "staticFolder": "static", "defaultPort": 3000, "cacheTTL": 30000, "sessionSecret": "REPLACE_ME_WITH_RANDOM_STRING" }
index.js
ファイルの現在のすべてのコンテンツを次のように変更します 。
ご注意
index.js
、アプリケーションを起動し、ポートでリクエストをリッスンする機能のみindex.js
残ります。
controllers
ディレクトリ
空の
JS
ファイルを作成します。
-
index.js
は、リクエスト処理およびHTMLレンダリングコントローラーです。
-
- 次のコードを
index.js
ファイルに追加します。
helpers
ディレクトリ
空の
JS
ファイルを作成します。
-
index.js
ヘルパーのエントリポイント。 -
twitter.js
-Twitter Search APIを操作するためのヘルパーモジュール。 -
youtube.js
-YouTube Data APIを操作するためのヘルパーモジュール。
-
middleware
ディレクトリ
空の
JS
ファイルを作成します。
-
auth.js
-YouTube認証検証モジュール。
-
OAuthトークンの取得
TwitterおよびGoogleサービスには、ツイート、Youtube上のビデオ、メールの手紙、写真など、さまざまなユーザーデータが保存されます。 他のアプリケーションまたはサードパーティのサービスからこのデータへの便利なアクセスを提供するために、彼らはOAuth 2.0オープン認証プロトコルを使用します 。
プロトコルに従って、開発者はOAuthサーバーにアプリケーションを登録し、特定のデータへのアクセスを要求します。 許可されたユーザーはそれを許可または拒否します。
Twitter用のOAuthトークンの取得
Twitterは、アプリケーション自体に代わって認証済みリクエストを発行する機能をアプリケーションに提供します。
どこから始めますか?
- ドキュメントを確認してください。
- アプリケーションを登録し、キー(コンシューマキー、コンシューマシークレット)を取得します。
- 便利な方法でPostmanをインストールします。
- Base64メソッドを使用して、
Consumer Key:Consumer Secret
文字列をエンコードします。 - コードと引き換えにOAuthトークンを取得します 。
Twitter Search APIへのリクエストで、受信したトークンとキーを使用します。
ご注意 Postmanは、Base64メソッドで受信したコードと引き換えにPOSTリクエストを使用してOAuthトークンを取得するのに役立ちます。
文字列をエンコードする方法は?
Base64メソッドを使用して文字列をエンコードするには:
次の形式の行を作成します:
Consumer Key:Consumer Secret
。
例
xvz1evFS4wEEPTGEFPHBog:L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg
ご注意 アプリケーションの [キーとアクセストークン]タブに移動して 、コンシューマキーとコンシューマシークレットキーを取得できます 。
- ターミナルまたはGit Bashを起動します。
- コマンド
echo -n "xvz1evFS4wEEPTGEFPHBog:L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg" | base64
実行しますecho -n "xvz1evFS4wEEPTGEFPHBog:L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg" | base64
echo -n "xvz1evFS4wEEPTGEFPHBog:L8qq9PZyRg6ieKGEKhZolGC0vJWLw8iEJ88DRdyOg" | base64
。 結果のコードをコピーします。
例
eHZ6MWV2RlM0d0VFUFRHRUZQSEdFS2hab2xHQzB2SldMdzhpRUo4OERSZHlPZw==
ご注意 問題がある場合は、 base64encode.orgオンラインリソースを使用してください 。
コードと引き換えにOAuthトークンを取得する方法は?
コードと引き換えにトークンを受け取るには:
Postmanを起動します。
ご注意 デフォルトでは、Twitter OAuthサーバーへのPOSTリクエストを生成する必要があるタブが開きます。
- POSTリクエストのタイプを選択します。
- サーバーアドレス
https://api.twitter.com/oauth2/token
入力します。 - [ヘッダー]タブに移動します。
値(値フィールド)
Basic < Consumer Key:Consumer Secret>
して、KeyフィールドにAuthorization
見出しを入力しBasic < Consumer Key:Consumer Secret>
。
例
Authorization: Basic eHZ6MWV2RlM0d0VFUFRHRUZQSEdFS2hab2xHQzB2SldMdzhpRUo4OERSZHlPZw==
ご注意 Basicは、基本的な認証方法を示します。
値
application/x-www-form-urlencoded;charset=UTF-8
の2番目のContent-Type
ヘッダーを入力しapplication/x-www-form-urlencoded;charset=UTF-8
。
例
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
- [ボディ]タブに移動します。
-
x-www-form-urlencoded
オプションを選択します。 - 「キー」フィールドに値
client_credentials
を持つgrant_type
リクエストgrant_type
を入力します。 送信ボタンをクリックします。
OAuthサーバーは、JSON形式でトークンを返します。
{ "token_type": "bearer", "access_token": "AAAAAAAAAAAAAAAAAAAAAA%2FAAAAAAAAAA%3DAAAAAAAAAAAAAAAAAA" }
重要! 受信したトークンとキー(コンシューマキーとコンシューマシークレット)を保存します。 これらは、アプリケーション構成ファイルに必要です 。
GoogleのOAuthトークンを取得する
Googleは、アプリケーション自体に代わって認証済みリクエストを発行する機能をアプリケーションに提供します。
ご注意 passport-youtube-v3モジュールは、認証コードと引き換えにPOSTリクエストを使用してOAuthトークンを受信および更新します。
どこから始めますか?
- ドキュメントを確認してください。
- アプリケーションを登録し、クライアントIDとクライアントシークレットを取得します 。
- アプリケーションアカウントにコールバックURL(この場合は
http://localhost:3000
)を入力します。 - YouTube Data APIへのリクエストでは、受信したクライアントIDとクライアントシークレットを使用します。
重要! 受信したキー(クライアントIDとクライアントシークレット)を保存します。 これらは、アプリケーション構成ファイルに必要です 。
アプリケーション構成
すべてのキーとトークンを受け取った後、それらをアプリケーション構成ファイルに追加する必要があります。
services
フィールドをserver/config.json
ファイルに追加します。
"services": { "twitter": { "consumer_key": "", "consumer_secret": "", "bearer_token": "" }, "youtube": { "client_id": "", "client_secret": "", "redirect_url": "http://localhost:3000" } }
- 同じ名前のフィールドに受信データを入力します 。
server/config.json
をGitバージョン管理システムから非server/config.json
して、ファイルリポジトリに誤って秘密キーを追加しないようにします。
# .gitignore server/config.json
Twitter Search APIの使用
Twitter Search APIを使用すると、Twitter.comで過去7日間に公開された最新または最も人気のあるツイートを見つけることができます。
APIを正常に呼び出すには、次の変更を行う必要があります。
controllers
ディレクトリ
helpers
ディレクトリ
次のコンテンツを
index.js
ファイルに追加します。
module.exports = { twitter: require('./twitter') };
-
twitter.js
ファイルに次のコードを追加します。
YouTube Data APIを使用する
YouTube Data APIを使用すると、Youtube.comで公開されているビデオを検索できます。 デフォルトでは、次のリソースが検索結果セットに含まれています:ビデオ、チャンネル、プレイリスト。
APIを正常に呼び出すには、次の変更を行う必要があります。
server
ディレクトリ
次のコードを
auth.js
ファイルに追加します。
routes.js
ファイルを編集します。
変更:
var router = require('express').Router(), controllers = require('./controllers'); router .get('/ping/', function(req, res) { res.send('ok'); }) .get('/', controllers.getContent); module.exports = router;
オン:
var router = require('express').Router(), controllers = require('./controllers'), passportYouTube = require('./auth'), middleware = require('./middleware/auth'), isAuthenticated = middleware.isAuthenticated; router .get('/auth/youtube', passportYouTube.authenticate('youtube')) .get('/auth/youtube/callback', passportYouTube.authenticate('youtube', { failureRedirect: '/error', failureFlash: true }), (req, res) => { res.redirect('/'); }) .get('/', isAuthenticated, controllers.getContent); module.exports = router;
controllers
ディレクトリ
helpers
ディレクトリ
次のコンテンツを
index.js
ファイルに追加します(コメントを参照)。
module.exports = { twitter: require('./twitter'), youtube: require('./youtube') // `youtube.js` };
- 次のコードを
youtube.js
ファイルに追加します。
middleware
ディレクトリ
auth.js
ファイルに次のコンテンツを追加します。
module.exports = { isAuthenticated: function(req, res, next) { if (req.isAuthenticated()) return next(); return res.redirect('/auth/youtube'); } };
レイアウト
レイアウトとクライアントのJavaScriptの問題を意図的に考慮しませんでした。 これにより、ボリュームが大きくなるため、この記事の実用的な価値は低くなります。
レイアウトプロセスは次の手順に簡略化されます。
-
common.blocks
ディレクトリからすべてのブロックを削除します。 - 次のブロックを
common.blocks
ディレクトリにcommon.blocks
ます。 - logo.svgを
static/images
ディレクトリに追加します。 - サーバーを再起動します:
npm run dev
。
社会サービス検索ロボットの準備ができました。
うまくいかなかった?
アプリケーションの作成中に問題が発生した場合は、 フォーラムで解決策を探してください 。 準備ができていない場合は、質問してください。