コードフォーマットを実行する
複数人で開発する場合には、全体の品質を保つために、各々が好きなスタイルでコードを書くことを避けるべきです。
コードフォーマットツールのデファクトスタンダードである Prettier を利用し、各ファイルが統一されたフォーマットに修正されることを確認しましょう。
ルートディレクトリに .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.json
の scripts
に prettier
コマンドを追加します。
...
"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
ファイルを新規作成し、次のコードをコピペします。
{
"env": {
"node": true,
"commonjs": true,
"es2021": true
},
"extends": "eslint:recommended",
"parserOptions": {
"ecmaVersion": 12
},
"rules": {}
}
package.json
の scripts
に eslint
コマンドを追加します。
...
"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 の標準的なスタイルを適用してみましょう。
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
に追加すると、表示がずれてしまうので注意です。
<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 です。詳しくは公式サイトを参照してください。
<!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 アプリをローカルで実行します。
http://localhost:5000/db にアクセスして、画面のスタイルが変わっていることを確認しましょう。
変更前
変更後
確認が終わったら、Heroku にデプロイして終了です。
git add .
git commit -m "Lv.1 completed"
git push heroku main
一通りの手順はわかりましたか?他の画面についても、色々試してみてください。