Next Actions

余裕があれば挑戦してみましょう。

コードフォーマットを実行する

複数人で開発する場合には、全体の品質を保つために、各々が好きなスタイルでコードを書くことを避けるべきです。

コードフォーマットツールのデファクトスタンダードである Prettier を利用し、各ファイルが統一されたフォーマットに修正されることを確認しましょう。

ルートディレクトリに .prettierrc ファイルを新規作成し、次のコードをコピペします。

.prettierrc
{
  "printWidth": 80,
  "tabWidth": 2,
  "useTabs": false,
  "semi": true,
  "singleQuote": true,
  "quoteProps": "as-needed",
  "jsxSingleQuote": false,
  "trailingComma": "none",
  "bracketSpacing": true,
  "jsxBracketSameLine": false,
  "arrowParens": "always",
  "requirePragma": false,
  "insertPragma": false,
  "proseWrap": "preserve",
  "htmlWhitespaceSensitivity": "css",
  "endOfLine": "lf",
  "overrides": [
    {
      "files": "*.html",
      "options": { "parser": "lwc" }
    }
  ]
}

package.jsonscriptsprettier コマンドを追加します。

package.json
...

"scripts": {
  "prettier": "prettier \"**/*.{css,html,js,json,md}\" --write --loglevel log",
  "start": "node index.js",
  "test": "node test.js"
},

...

prettier をローカルにインストールし、実行します。

npm install --save-dev prettier

npm run prettier

それぞれのファイルでコードがどのように修正されたのかを確認します。

以後、コードを変更するたびに Prettier を実行することで均一的なフォーマットを維持することを習慣化しましょう。

静的コード解析を実行する

コードフォーマットを合わせたら、次はコードの書き方にこだわりましょう。せっかくコードを書くのであれば、先人の叡智が詰まった規約に準拠した書き方をお勧めします。潜在的なバグを事前に潰しておくことにも繋がります。

JavaScript の静的コード解析ツールのデファクトスタンダードである ESLint を利用し、コードが規約に違反していないかどうか確認しましょう。

ルートディレクトリに .eslintrc.json ファイルを新規作成し、次のコードをコピペします。

.eslintrc.json
{
  "env": {
    "node": true,
    "commonjs": true,
    "es2021": true
  },
  "extends": "eslint:recommended",
  "parserOptions": {
    "ecmaVersion": 12
  },
  "rules": {}
}

package.jsonscriptseslint コマンドを追加します。

package.json
...

"scripts": {
  "eslint": "eslint *.js --format html --output-file .reports/eslint.html",
  "prettier": "prettier \"**/*.{css,html,js,json,md}\" --write --loglevel log",
  "start": "node index.js",
  "test": "node test.js"
},

...

eslint をローカルにインストールし、実行します。

npm install --save-dev eslint

npm run eslint

それぞれのファイルでコードがどのような警告が表示されるのかを確認します。

また、.reports フォルダ内に生成されている eslint.html をブラウザで開くと、警告を一覧表示することができます。

コードを修正し、警告が消えたことを確認します。

以後、コードを変更するたびに ESLint を実行することで警告の有無を確認し、コードを修正することを習慣化しましょう。なお、コードを修正せずに警告だけを消す方法もありますが、可能な限りコードを修正するようにしましょう。

Lightning Design System を適用する

今回のチュートリアルで作成された画面はとてもシンプルですので、Salesforce の標準的なスタイルを適用してみましょう。

もっと詳しく知りたい場合は、公式のチュートリアルを試してみてください。

https://www.lightningdesignsystem.com/platforms/heroku/

Salesforce Lightning Design System (SLDS) を npm 経由でダウンロードし、public/assets/ 配下にコピーします。

npm install @salesforce-ux/design-system --save-dev

cp -r node_modules/@salesforce-ux/design-system/assets/ public/assets/

SLDS を適用するために、views/partials/header.ejs の最下部にコードを追加します。

views/pages/db.ejs に追加すると、表示がずれてしまうので注意です。

header.ejs
<title>Node.js Getting Started on Heroku</title>
<link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
<script type="text/javascript" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
<link rel="stylesheet" type="text/css" href="/stylesheets/main.css" />
<link rel="stylesheet" type="text/css" href="/assets/styles/salesforce-lightning-design-system.css" />

views/pages/db.ejs のコードを修正します。長いので、コピペしてください。

今回利用するコンポーネントは Cards と Data Tables です。詳しくは公式サイトを参照してください。

db.ejs
<!DOCTYPE html>
<html>
<head>
  <%- include ("../partials/header.ejs") %>
</head>

<body>

<%- include ("../partials/nav.ejs") %>

<div class="container">
<!-- <h2>Database Results</h2> -->
<article class="slds-card">
  <div class="slds-card__header slds-grid">
    <header class="slds-media slds-media_center slds-has-flexi-truncate">
      <div class="slds-media__figure">
        <span class="slds-icon_container slds-icon-standard-account" title="account">
          <svg class="slds-icon slds-icon_small" aria-hidden="true">
            <use xlink:href="/assets/icons/standard-sprite/svg/symbols.svg#account"></use>
          </svg>
          <span class="slds-assistive-text">Database Results</span>
        </span>
      </div>
      <div class="slds-media__body">
        <h2 class="slds-card__header-title">
          <a href="#" class="slds-card__header-link slds-truncate" title="Database Results">
            <span>Database Results</span>
          </a>
        </h2>
      </div>
    </header>
  </div>
  <div class="slds-card__body slds-card__body_inner">
    <!-- <ul>
      <% results.forEach(function(r) { %>
          <li><%= r.id %> - <%= r.name %></li>
      <% }); %>
    </ul> -->
    <table aria-multiselectable="true" class="slds-table slds-table_bordered slds-table_fixed-layout slds-table_resizable-cols" role="grid">
      <thead>
        <tr class="slds-line-height_reset">
          <th class="slds-text-align_right" scope="col" style="width:3.25rem">
            <span id="column-group-header" class="slds-assistive-text">Choose a row</span>
            <div class="slds-th__action slds-th__action_form">
              <div class="slds-checkbox">
                <input type="checkbox" name="options" id="checkbox-unique-id-1465" value="checkbox-unique-id-1465" tabindex="0" aria-labelledby="check-select-all-label column-group-header" />
                <label class="slds-checkbox__label" for="checkbox-unique-id-1465" id="check-select-all-label">
                  <span class="slds-checkbox_faux"></span>
                  <span class="slds-form-element__label slds-assistive-text">Select All</span>
                </label>
              </div>
            </div>
          </th>
          <th aria-label="id" aria-sort="none" class="slds-is-resizable slds-is-sortable" scope="col">
            <a class="slds-th__action slds-text-link_reset" href="#" role="button" tabindex="0">
              <span class="slds-assistive-text">Sort by: </span>
              <div class="slds-grid slds-grid_vertical-align-center slds-has-flexi-truncate">
                <span class="slds-truncate" title="id">id</span>
                <span class="slds-icon_container slds-icon-utility-arrowdown">
                  <svg class="slds-icon slds-icon-text-default slds-is-sortable__icon " aria-hidden="true">
                    <use xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"></use>
                  </svg>
                </span>
              </div>
            </a>
            <div class="slds-resizable">
              <input type="range" aria-label="id column width" class="slds-resizable__input slds-assistive-text" id="cell-resize-handle-2668" max="1000" min="20" tabindex="0" />
              <span class="slds-resizable__handle">
                <span class="slds-resizable__divider"></span>
              </span>
            </div>
          </th>
          <th aria-label="name" aria-sort="none" class="slds-is-resizable slds-is-sortable" scope="col">
            <a class="slds-th__action slds-text-link_reset" href="#" role="button" tabindex="0">
              <span class="slds-assistive-text">Sort by: </span>
              <div class="slds-grid slds-grid_vertical-align-center slds-has-flexi-truncate">
                <span class="slds-truncate" title="name">name</span>
                <span class="slds-icon_container slds-icon-utility-arrowdown">
                  <svg class="slds-icon slds-icon-text-default slds-is-sortable__icon " aria-hidden="true">
                    <use xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#arrowdown"></use>
                  </svg>
                </span>
              </div>
            </a>
            <div class="slds-resizable">
              <input type="range" aria-label="name column width" class="slds-resizable__input slds-assistive-text" id="cell-resize-handle-2669" max="1000" min="20" tabindex="0" />
              <span class="slds-resizable__handle">
                <span class="slds-resizable__divider"></span>
              </span>
            </div>
          </th>
          <th class="" scope="col" style="width:3.25rem">
            <div class="slds-truncate slds-assistive-text" title="Actions">Actions</div>
          </th>
        </tr>
      </thead>
      <tbody>
        <% results.forEach(function(r) { %>
          <tr aria-selected="false" class="slds-hint-parent">
            <td class="slds-text-align_right" role="gridcell">
              <div class="slds-checkbox">
                <input type="checkbox" name="options" id="checkbox-<%= r.id %>" value="checkbox-<%= r.id %>" tabindex="0" aria-labelledby="check-button-label-01 column-group-header" />
                <label class="slds-checkbox__label" for="checkbox-<%= r.id %>" id="check-button-label-<%= r.id %>">
                <span class="slds-checkbox_faux"></span>
                <span class="slds-form-element__label slds-assistive-text">Select item <%= r.id %></span>
              </label>
            </div>
          </td>
          <th scope="row">
            <div class="slds-truncate" title="id">
              <a href="#" tabindex="0"><%= r.id %></a>
            </div>
          </th>
          <td role="gridcell">
            <div class="slds-truncate" title="name"><%= r.name %></div>
          </td>
          <td role="gridcell">
            <button class="slds-button slds-button_icon slds-button_icon-border-filled slds-button_icon-x-small" aria-haspopup="true" tabindex="0" title="More actions">
              <svg class="slds-button__icon slds-button__icon_hint slds-button__icon_small" aria-hidden="true">
                <use xlink:href="/assets/icons/utility-sprite/svg/symbols.svg#down"></use>
              </svg>
              <span class="slds-assistive-text">More actions</span>
            </button>
          </td>
        </tr>
        <% }); %>
      </tbody>
    </table>
  </div>
  <footer class="slds-card__footer"></footer>
</article>
</div>

</body>
</html>

表示するデータを増やすために、Heroku Postgres にテストデータを複数件インサートします。

heroku pg:psql

insert into test_table values (2, 'hello world');
insert into test_table values (3, 'hello heroku');
insert into test_table values (4, 'hello salesforce');
insert into test_table values (5, 'hello ohana');

exit

Heroku アプリをローカルで実行します。

heroku local web

http://localhost:5000/db にアクセスして、画面のスタイルが変わっていることを確認しましょう。

変更前

変更後

確認が終わったら、Heroku にデプロイして終了です。

git add .
git commit -m "Lv.1 completed"
git push heroku main

一通りの手順はわかりましたか?他の画面についても、色々試してみてください。

最終更新