※ これから記載する事項は、私が所属する会社とは一切関係のない事柄です。
今回の記事では、SFRAに対してデザインの修正を行いたい場合やクライアントサイドに新しく機能を追加したい場合の方法を紹介したいと思います。
前提としてSFRAについて知っておいた方がいいこと
① app_storefront_base のコードは修正しないようにしましょう
SFRAでは app_storefront_base
というカートリッジを使用していますが、そのカートリッジ内のソースコードを修正してしまうと、後の SFRA アップデートに影響が出たり、その他想定外の影響が出ることがありますので、修正しないようにしましょう。
② Bootstrap 4 を利用しています
SFRA では NPM レジストリ上の bootstrap 4 をインポートして利用しています。そのためグリッドシステムやその他の多くのコンポーネントを利用できます。
③ jQuery を利用しています
SFRA では NPM レジストリ上の jQuery をインポートして利用しています。クライアントサイドでの機能追加は基本的にはjQueryを利用して行います。
④ static フォルダに静的ファイルは設置します
SFRA では CSS / JS / Image / Font などの静的ファイルは static フォルダに設置して利用します。(もちろん商品画像やバナー画像などは別です)
⑤ SCSS を利用します
SFRA では SCSS ファイルをコンパイルし、static フォルダ内に CSS ファイルを生成してスタイルを適用します。
JS, SCSS のコンパイルについては Webpack を利用していますが、sgmf-scripts というコマンドを通して利用できますので、前回紹介した記事をご覧ください。
JS の作成
JS は cartridge/client/default/js
フォルダ内に作成しますが、
基本的には下記のようなフォルダ構成になります。(箇条書きで書いているので若干分かりにくくてすみません。。)
・ /cartridge/client/default/js
・ モジュール1
・ モジュール1.js
・ モジュール2
・ モジュール2.js
・ モジュールをインポートしてISMLでインポートされる.js
シンプルな例を作成してみます。下記のようなフォルダ構成になっているとします。
・ /cartridge/client/default/js
・ module
・ module.js
・ sample.js
下記のようにモジュールを作成します。 bindSomething
のように関数を設定するとページが読み込まれた後に実行されるのでここで HTML にイベントをバインドすることが多いです。また、methods
のようにオブジェクトを設定しているとページ読み込み後に呼び出されませんので、クライアントでの操作時に実行したい関数などを定義できます。
module.exports = {
bindSomething: function () {
$('.sample').on('click', function () {
// Do shomething.
});
},
methods: {
sampleMethod: function(){
// Do shomething.
},
}
}
作成したモジュールは下記のようにインポートしてきます。
'use strict';
var processInclude = require('base/util');
$(document).ready(function () {
processInclude(require('./module/module'));
});
作成した JS ファイルがコンパイルされて生成された sample.js
を ISML ファイルで下記のように呼び出して利用します。
<isdecorate template="common/layout/page">
<isscript>
var assets = require('*/cartridge/scripts/assets.js');
assets.addJs('/js/sample.js');
</isscript>
==OMIT==
</isdecorate>
SCSS の作成
SCSS も JS に似ていて、 cartridge/client/default/scss
フォルダ内に作成しますが、
基本的には下記のようなフォルダ構成になります。(たまにモジュールのフォルダから直接 ISML でインポートすることもあります。)
・ /cartridge/client/default/scss
・ モジュール1
・ _モジュール1.scss
・ モジュール2
・ モジュール2.scss
・ モジュールをインポートしてISMLでインポートされる.scss
シンプルな例を作成してみます。下記のようなフォルダ構成になっているとします。
・ /cartridge/client/default/scss
・ module
・ _module.scss
・ sample.scss
下記のようにモジュールを作成します。Bootstrap などのライブラリモジュールの呼び出しも可能です。
@import "bootstrap/scss/variables";
@import "bootstrap/scss/mixins/breakpoints";
.someClass {
// Some style.
}
作成したモジュールは下記のようにインポートしてきます。
@import "module/module";
作成した SCSS ファイルがコンパイルされて生成された sample.css
を ISML ファイルで下記のように呼び出して利用します。
<isdecorate template="common/layout/page">
<isscript>
var assets = require('*/cartridge/scripts/assets.js');
assets.addCss('/css/sample.css');
</isscript>
==OMIT==
</isdecorate>
Tips
ISML からインポートされないようなパーシャル SCSS ファイルはお作法として _
(アンダーバー) をプリフィックスとしてつけた方が良さそうです。(参考)
SFRA の CSS の上書き
例えば、app_custom_sample
というカートリッジを作成してホームページの CSS を上書きたいとします。
SFRA のデフォルトのホームページは下記の SCSS を利用しています。
app_storefront_base/cartridge/client/default/scss/homePage.scss
CSS を上書きする場合はカスタムカートリッジの同じ階層に同じファイル名のファイルを作成します。
app_custom_sample/cartridge/client/default/scss/homePage.scss
そして下記のように、@import "base/homePage";
で SFRA の SCSS をインポートしてから上書きを行います。
@import "base/homePage";
.page-title {
color:red !important;
}
Bootstrap の利用
基本的にはサイト上に記載のあるのコンポーネントは使用できます。
例えばサンプルにあるアラートの HTML を下記のように ISML に記載します。
<div class="alert alert-primary" role="alert">
A simple primary alert—check it out!
</div>
すると、下記のようにスタイルが適用された状態で表示されます。
Tips
一部コメントアウトされて利用できないものもありました。( コード (Account Manager アカウント必要))
この場合は、main.js
を修正する必要があります。例えば、app_custom_sample/cartridge/client/default/js/main.js
を作成して下記のように記載します。
require('base/main');
require('bootstrap/js/src/tooltip.js');
すると下記のように Bootstap の API を呼び出せます。
$('[data-toggle="tooltip"]').tooltip();
SFRA の JS の上書き
例えば商品詳細ページの JS を上書きしたいとします。
まず、SFRA の商品詳細ページでは、app_storefront_base/cartridge/client/default/js/productDetail.js
を読み込んでおり、さらにこの JS はモジュールとして、app_storefront_base/cartridge/client/default/js/product/detail.js
を読み込んでいます。
上書きする場合は、下記のようにファイルを作成します。
まず、productDetail.js
をコピーしてきます。今回はそのまま使いますが、SFRA のモジュールをそのまま使う場合は、
processInclude(require('base/hoge'));
のようにルートのエイリアスに base
を使うように変更しましょう。
'use strict';
var processInclude = require('base/util');
$(document).ready(function () {
processInclude(require('./product/detail'));
});
今回は、detail.js
の関数 showSpinner
を上書きしたいと思います。完全に上書きしたい場合は、base.showSpinner()
の部分は消しても良いかと思います。
'use strict';
var base = require('base/product/detail');
module.exports = {
...base,
showSpinner: function () {
base.showSpinner()
// Add logic.
},
};
サイト全体の CSS、JS 修正
SFRA でサイト全体に適用されている CSS, JS は、global.scss
, skin.scss
, main.js
です。
あくまで私の所感 ですが、この中で、global.scss
と main.js
はあくまでモジュールのインポートに徹した方がいいような気がします。
例えば、下記のような使い方です。
global.scss
では下記のように自作の変数やモジュール、ライブラリのモジュールをインポートするために使う。
@import "base/global";
@import "variables";
@import "custom/custom";
skin.scss
では、カスタムプロパティの上書きやちょっした CSS の追加として使う。
@import "base/skin/skin";
:root {
--skin-banner-background-color-1: #3f0a00;
--skin-banner-background-color-2: #000009;
}
.hoge {
// Some code
}
main.js
は自作のモジュールやライブラリのモジュールをインポートするために使う。
require('base/main');
$(document).ready(function () {
processInclude(require('./custom/custom'));
});
require('bootstrap/js/src/tooltip.js');
スクリプトを追加したい
Google Analytics などの CDN で提供されているようなライブラリをインポートしたい場合やちょっとしたスクリプトを埋め込みたい時があるかと思います。
そういった場合に便利なのが SFRA であらかじめ用意されている Hooks を利用することです。
Hooks の利用方法については以前のQiitaをご参照ください。
追加場所としては下記の2つがあり、それぞれに Hook 名があります。
- head タグ内
- app.template.afterFooter
- footer タグの後
- app.template.htmlHead
まず下記のように、htmlHead
, afterFooter
と言う名前の関数名でエクスポートしたJSを作成します。
下記の例では、footer タグの後には、Business Manager の マーチャントツール > サイト環境設定 > カスタムサイト環境設定グループ で設定した値(SampleSnippet
)をレンダリングしており、head タグ内には、hooks/afterFooter
テンプレートの中身をレンダリングしています。
const Site = require('dw/system/Site');
const velocity = require('dw/template/Velocity');
var ISML = require('dw/template/ISML');
const afterFooter = function () {
const currentSite = Site.current;
const snippet = currentSite.getCustomPreferenceValue('SampleSnippet');
if (snippet) {
velocity.render(snippet, null);
}
};
function htmlHead(params) {
var templateName = 'hooks/afterFooter';
try {
ISML.renderTemplate(templateName, params);
// Another option is to render using Velocity templates
/*
params.message = params.message || 'world';
velocity.render('Hello $message', params);
*/
} catch (e) {
Logger.error('Error while rendering template ' + templateName);
}
}
exports.htmlHead = htmlHead;
exports.afterFooter = afterFooter;
呼び出す際は下記のように hooks.json
の設定をお忘れなく。
{
"hooks": [
{
"name": "app.template.afterFooter",
"script": "~/cartridge/scripts/hooks/sampleTemplate"
},
{
"name": "app.template.htmlHead",
"script": "~/cartridge/scripts/hooks/sampleTemplate"
}
]
}