- 投稿日:2020-02-26T23:07:01+09:00
【DX】Ryzen9 3950xは開発体験をどれほど向上させるか
Ryzen9 3950xは開発体験をどれほど向上させるか
はじめに
AMD Ryzenの登場の登場により、それまでIntel寡占状態だったCPU業界の動きがかなり激しくなっています。僕も先日「AMD Ryzen9 3950x」搭載のデスクトップPCを購入しました。
「AMD Ryzen 9 3950X」はメインストリーム向けCPUとして、世界初の16コア32スレッドCPUです。そんな驚異的な性能でどのくらい開発体験が向上するかを検証していきたいと思います。比較環境
パッと思いつく検証方法がなかったのでReactのbuild時間を計測することにしました。
自作PCにはmacOSを搭載することができないのでUbuntuOSを利用しています。検証PC
PC CPU OS Memory iMac 2019 Intel(R) Core(TM) i5-8500 CPU @ 3.00GHz macOS 10.15.3 40GB MacBook Pro 2017 Intel(R) Core(TM) i7-7660U CPU @ 2.50GHz macOS 10.15.3 16GB Ryzen9 3950X PC AMD Ryzen™ 9 3950X Ubuntu 18.04 32GB ビルド対象
項目 値 言語 JavaScript フレームワーク React bundler webpack Node Version 10.16.3 ファイル数 1404 行数 133363 結果
Development Build
まずは
Development Build
で検証します。
以下のコマンドを実行したときにブラウザでロードされるまでの時間をキャッシュ有(1回目)とキャッシュ無(2回目)計測します。$ yarn start
- キャッシュ無
PC Time Macbook Pro 4:01.04 iMac 1:01.53 3950x PC 0:42.63
- キャッシュ有
PC Time Macbook Pro 1:44.14 iMac 0:41.78 3950x PC 0:30.82 Production Build
まずは
Production Build
で検証します。
以下のコマンドを実行したときにbundleファイルが生成され終わるまでの時間を計測します。$ yarn build
PC 1回目 Macbook Pro 4:40.63 iMac 2:32.74 3950x PC 1:42.44 まとめ
じつはこの3台、購入時期は差があるものの値段的にはあまり差がありません。
OSは違えどRyzenのコストパフォーマンの高さがうかがえますね。そもそもデスクトップPCとノートパソコンではCPUの設計が異なります。型番の最後に"U"がつくとそれはモバイル用に設計された省電力CPUなのであまりパフォーマンスがでません。そのぶんMacBookProは持ち運ぶことができますが。
1日に2回キャッシュ無、10回キャッシュ有ビルドをした場合、
最速のRyzenとMacBookでは一日あたり20分、一年で120時間の差にになります。
それ以外の差も含めるともっと差がでることになります。ゲーム業界やデザイナー業界だけでなく、デベロップ環境でもAMDの勢いを感じることができました。
AMD最高です。
- 投稿日:2020-02-26T23:07:01+09:00
【DX】Ryzen9 3950Xは開発体験をどれほど向上させるか
Ryzen9 3950Xは開発体験をどれほど向上させるか
はじめに
AMD Ryzenの登場により、それまでIntel寡占状態だったCPU業界の動きがかなり激しくなっています。僕も先日「AMD Ryzen9 3950X」搭載のデスクトップPCを購入しました。
「AMD Ryzen9 3950X」はメインストリーム向けCPUとして、世界初の16コア32スレッドCPUです。そんな驚異的な性能でどのくらい開発体験が向上するかを検証していきたいと思います。比較環境
パッと思いつく検証方法がなかったのでReactのbuild時間を計測することにしました。
自作PCにはmacOSを搭載することができないのでUbuntuOSを利用しています。検証PC
PC CPU OS Memory iMac 2019 Intel(R) Core(TM) i5-8500 CPU @ 3.00GHz macOS 10.15.3 40GB MacBook Pro 2017 Intel(R) Core(TM) i7-7660U CPU @ 2.50GHz macOS 10.15.3 16GB Ryzen9 3950X PC AMD Ryzen™ 9 3950X Ubuntu 18.04 32GB ビルド対象
項目 値 言語 JavaScript フレームワーク React bundler webpack Node Version 10.16.3 ファイル数 1404 行数 133363 結果
Development Build
まずは
Development Build
で検証します。
以下のコマンドを実行したときにブラウザでロードされるまでの時間をキャッシュ有(1回目)とキャッシュ無(2回目)計測します。$ yarn start
- キャッシュ無
PC Time Macbook Pro 4:01.04 iMac 1:01.53 3950x PC 0:42.63
- キャッシュ有
PC Time Macbook Pro 1:44.14 iMac 0:41.78 3950x PC 0:30.82 Production Build
つぎに
Production Build
で検証します。
以下のコマンドを実行したときにbundleファイルが生成され終わるまでの時間を計測します。$ yarn build
PC 1回目 Macbook Pro 4:40.63 iMac 2:32.74 3950x PC 1:42.44 まとめ
じつはこの3台、購入時期は差があるものの値段的にはあまり差がありません。
OSは違えどRyzenのコストパフォーマンの高さがうかがえますね。そもそもデスクトップPCとノートパソコンではCPUの設計が異なります。型番の最後に"U"がつくとそれはモバイル用に設計された省電力CPUなのであまりパフォーマンスがでません。そのぶんMacBookProは持ち運ぶことができますが。
1日に2回キャッシュ無、10回キャッシュ有ビルドをした場合、
最速のRyzenとMacBookでは一日あたり20分、一年で120時間の差にになります。
それ以外の差も含めるともっと差がでることになります。ゲーム業界やデザイン業界だけでなく、デベロップ環境でもAMDの勢いを感じることができました。
AMD最高です。
- 投稿日:2020-02-26T21:27:29+09:00
Top 50+ React Native Interview Questions and Answers 2020
Have a look at these mostly asked best 50+ React Native Interview Questions and their answers in 2020. Get ready to face any question on React Native thrown at you in the interview.
click here to read more
https://www.positronx.io/top-react-native-interview-questions-and-answers/
- 投稿日:2020-02-26T21:25:23+09:00
Top 40+ Spring Boot Interview Questions & Answers 2020
most asked Spring Boot Interview Questions with Answers list of 2020.
click here to read more
https://www.positronx.io/top-spring-boot-interview-questions-answers/
- 投稿日:2020-02-26T21:23:49+09:00
Top 30+ CSS & CSS3 Interview Questions and Answers 2020
Mostly asked CSS & CSS3 Interview Questions with Answers in 2020. Reading these questions once will give you a ton of confidence, and you will be ready to move out for an interview. Let’s begin.
click here to read more
https://www.positronx.io/top-css-css3-interview-questions-and-answers/
- 投稿日:2020-02-26T21:10:09+09:00
React Native Firebase - Firebase Integration in React Native
React Native is a well known open-source framework created by Facebook. It allows you to build a native mobile application with the help of JavaScript.
clic here to read more
https://www.positronx.io/react-native-firebase-firebase-integration-in-react-native/
- 投稿日:2020-02-26T21:08:50+09:00
Top 30 Python Interview Questions with Answers 2020
Here are the top 30 python interview questions and answers in 2020 you should read before appearing in the interview.
click here to read more
https://www.positronx.io/python-interview-questions-with-answers/
- 投稿日:2020-02-26T21:01:33+09:00
Create Radio Button Component in React Native
This tutorial shows you how you can create a radio button component in React Native application pretty smoothly. We will learn the easiest way to deal with React Native Radio Buttons.
Read more to click here
https://www.positronx.io/create-radio-button-component-in-react-native/
- 投稿日:2020-02-26T20:45:20+09:00
three.js でタッチ系のイベントが発火しない時
環境
three.js - 113
困ったこと
click
に設定したイベントがマウスクリックでは問題ないのに、タッチで発火しないという事象に悩まされる。こんな感じでイベントを設定↓
window.addEventListener('click', () => { // 発火せず });ちなみに、タッチ系もだめだった↓
window.addEventListener('touchstart', Callback);// 発火せず原因
three.jsにサンプルとして付属している
OrbitControls
を使っていることが原因。
内部で各種イベント伝播が 「食べられて」しまう実装になっている。「食べられて」が正しいのか知りませんが、こちらのIssueで気に入ったので使っていきます。
https://github.com/mrdoob/three.js/issues/16254対策
OrbitControls.js
からevent.preventDefault()
を削除することで、イベントを食べられないようにすることができます。https://github.com/mrdoob/three.js/blob/dev/examples/js/controls/OrbitControls.js
OrbitControls.jsfunction onTouchStart( event ) { if ( scope.enabled === false ) return; // ↓こいつが邪魔なのでコメントアウト // event.preventDefault(); // prevent scrolling switch ( event.touches.length ) {これで、
click
に設定したイベント処理が実行されタッチパネルでも問題なく動くようになりました。ちなみに、この変更による副作用も存在するようなのでご自身の環境で問題ないことを確認してくださいね。
(私の環境では特に問題なかった。多分)
https://github.com/mrdoob/three.js/pull/18612
- 投稿日:2020-02-26T16:51:17+09:00
[ES5]多くのWebエンジニアができていないクライアントサイドの書き方(JavaScriptのアンチパターン等) ES5
フリーのエンジニアです。
出向先でクライアントサイドについて話す事がありましたので、記事にしました。
ES5に関する記事なので、古いブラウザ(ie11など)に対応することを想定してください。
メモした内容をそのまま貼り付けてます。わかりにくいかも。厳密等値演算子を使おう
==,!= はアンチパターン
Promiseを使おう
ES5でもpolyfillを利用すれば、Promiseは使える
積極的に使う事クラスの書き方
コンストラクタはこう書く var MyClass = function() { ... };
メソッドはこう書く #MyClass.prototype.methodA = function() { ... };組み込みオブジェクト(Mathのようなオブジェクトを作りたい時)の書き方
モジュールパターンを使うとよい
varをいくつも書かない
カンマで区切ろう
varのスコープは関数スコープ
ブロックスコープはES5には無いよ。
なるべく、関数の先頭にvarを書く配列の初期化は[]
new Array()と書いてはいけない。オブジェクトの初期化は{}。new Object() と書いてはいけない。
配列のループ処理は、foreach,reduce等を使う
for文は仕方なく使う感じ
call,applyを使いこなすと便利 thisを固定できる
thisは動的に決まる
thisを正しく理解する事1モジュール1ファイルという決まりは無い
クラスのメソッドがたくさんある場合、機能別に別ファイルにしても構わない
プログラムのエントリポイントは意識せよ
エントリポイントは1箇所にすべき
jQueryを使っているなら、
$(function() { });
これの呼び出しは1箇所にして、ここで全部初期化しましょう。グローバル変数はなるべく少なくしよう
サーバーが生成する変数は1つのオブジェクトで受け取ろう
クライアントサイドMVCを意識してプログラミングしよう。
見通しが良くなります
悪い例 ビューに変数を埋め込む事同じ処理を2回以上書かない
当たり前の事ですが、できていない人が多すぎる。関数にしましょう。
$(selector)の戻り値は配列ではない
配列ではありません。オブジェクトのような配列です。(object-like array)
ES5でもデフォルト引数のようなことできる
function test(a) { a = a || 10 } // 引数が正の整数を期待している場合のサンプル
- 投稿日:2020-02-26T16:26:02+09:00
JavaScriptのメモ
これは何?
個人的なメモです。
置換
repelace (非破壊)
let some_word = '123456789' some_word.replace(/4567/, '') > "12389" console.log('some_word=[%s]', some_word) > some_word=[123456789]Array
破壊を非破壊処理にする
let some_array = [1, 2, 3, 4, 5, 6, 7, 8] some_array.pop() // 破壊 some_array.slice().pop() // 非破壊サイズ指定&同じ数値で初期化
let N = 10 let init_num = 0 let some_array = new Array(N).fill(0)Math.max()
let some_array = [1, 2, 3, 4, 5, 6, 7, 8] let max_num = Math.max(...some_array)数値としてsort() [破壊]
let some_array = [9, 1, 12, 13, 4, 15, 6, 7, 8] // 破壊 some_array.sort( (a, b) => { return a - b }) // 昇順 some_array.sort( (a, b) => { return b - a }) // 降順forEachでkey,value
let some_array = [9, 1, 12, 13, 4, 15, 6, 7, 8] some_array.forEach( (val, key) => { console.log('key=[%s] val=[%i]', key, val) })要素分割
let some_array = [9, 1, 12, 13, 4, 15, 6, 7, 8] some_array.slice().splice(3, 5) // index=3 から 5 要素 > (3) [13, 7, 8] some_array.slice().slice(5) // index=6 から最後までの要素 > (4) [15, 6, 7, 8]Object
ObjectのキーをArrayで取得
let some_obj = { a: 0, b: 1, c: 2 } let keys = Object.keys(some_obj)ObectをforEach
let some_obj = { a: 0, b: 1, c: 2 } Object.keys(some_obj).forEach( key => { let val = some_obj[key] console.log('key=[%s] val=[%i]', key, val) })console
%s : String %d or %i : Number %f : Floating points %o : an Object %j : JSONReference
- 投稿日:2020-02-26T16:25:09+09:00
JavaScriptでフォーカスイン/アウトを自動的に行う
はじめに
WEB画面の入力項目には、フォーカスアウト時のイベントを定義することができます。
自動的にフォーカスイン/アウトを行えば、画面の初期表示時に動作させることも可能です。やったこと
JavaScriptでフォーカスイン/アウトを自動的に行う実装をしました。
document.form.item01.focus(); document.form.item01.blur();わかったこと
フォーカス関連のイベントを呼び出す場合は、formタグのname属性、inputタグのname属性を使用する。
つぎにやること
入力項目のフォーカスアウト時のイベントをピタゴラスイッチ的に呼び出す。
メリット
入力項目のフォーカスアウト時のイベントを流用できる。
- 投稿日:2020-02-26T16:14:12+09:00
JavaScriptでjpGridの列をカンマ区切りで結合する
はじめに
JavaScriptには、jpGridというグリッドテーブルを扱うライブラリがあります。
グリッドテーブル内の値をカンマ区切りで結合し、任意の項目に挿入しました。やったこと
JavaScriptでjpGridの列をカンマ区切りで結合しました。
var gt = $("#gt").getRowData(); var result = ''; for(var i=0; i<gt.length; i++){ result += gt[i].item01; if(i < gt.length - 1) result +=', '; } document.getElementsByName('item02')[0].value = result;わかったこと
jpGridのgetRowData()の結果は配列で返ってくるため、配列の長さを取得したりfor文で繰り返しをすることができる。
つぎにやること
カンマ区切りで結合した項目を一覧画面などに表示する
メリット
一覧画面でグリッドテーブル内の値を検索することができる
- 投稿日:2020-02-26T15:31:20+09:00
静的なWEBサイト用にも使えるstorybookのpug環境を作ってみた
storybookって色々使い道があると思うのですが、動的なWEBサイト用の情報しか殆どないので静的WEBサイトでも使えるようなものを作ってみました。
やりたい事が形になったので紹介したいと思います。
gitも公開しているので良かったお試しください。DEMO
https://github.com/BigFly3/storybook_html_pugdev出来ること
・/stories以下のtree-title.stories.pugを/path/to/tree-titleへ自動追加(日本語も可)
・/stories以下のsassやstylusを自動で読み込み
・パネルにpugとhtmlのソース表示&コピー
・pugのmixinでコンポーネント作成し、knobsやテストをjsで記述可
・複数の環境に合わせて設定を変更して構築可サブの環境として使えます
(.stories.)pug + sass,stylus + 一応jqueryを使えるようにしてあるので、storybookやjsの知識があまり無い状態でも、マークアップからstorybook上での開発が進められるようにしてあります。
プロジェクトの本環境を作成している間に、コンポーネントを先に開発してもらったりや既存のgulp環境などの横に並べて、stories以下のファイルを本環境でincludeして使用するみたいなことも可能になると思います。pugとhtmlのソース表示&コピー
アドオンのパネルにpugとhtmlのソースを表示することができます。
※自作のpugパネルはホットリロードが効きません。変更確認したい場合はリロードしてください。pugパネルのソース追加方法
【.stories.pug】で追加したストーリー → 自動的にパネルに追加されます
【.stories.js】で追加したストーリー → parametersの【pugCode】に/stories/以下のパスを入れる//csf export const Default = () => {/省略/} Default.story = { parameters:{pugCode:'Examples/Media/Media.pug'} } //storiesOf storiesOf('Examples/Media',modules) .add('Media', () => {/省略/}, {pugCode:'Examples/Media/Media.pug'})pugのmixinで作るコンポーネント
静的なHTMLのためのコンポーネント駆動開発と言う記事がとても参考になるのですが、pugのmixinを使用することでstorybookの形に合うコンポーネント作成をすることが出来ます。
※こちらの記事のテスト以外の動作サンプルも一緒に入れてあります。リンクボタンの作成サンプル
大中小サイズ、横幅フルサイズ、色、URL、外部リンクの設定ができるコンポーネントをpugのmixinで作成します。
/stories/Components/LinkButton/LinkButton.pugmixin LinkButton(params={}) - const props = Object.assign({ url: '' ,full:false}, params) //デフォルトのパラメータ - let className = attributes.class !== undefined ? attributes.class : '' - if(props.size) className += ' LinkButton--' + props.size - if(props.full) className += ' LinkButton--full' - if(props.color) className += ' LinkButton--' + props.color - if(props.isBlank) Object.assign( attributes , {'target':'_blank'}) - const attrs = Object.assign( attributes , {class:className}) a.LinkButton(href=props.url)&attributes(attrs) block/stories/Components/LinkButton/LinkButton.styl.LinkButton padding 10px 50px text-decoration none color #000000 position relative text-align center border 1px solid #CCCCCC border-radius 5px font-size 16px display inline-flex justify-content center align-items center box-sizing border-box /* サイズ */ &--small padding 5px 50px font-size 12px &--large font-size 24px /* フルサイズ */ &--full width 100% /* カラー */ &--gray background #8c9094 border 1px solid #8c9094 color #ffffff &--green background green border 1px solid #FFF color #ffffffこんな感じmixinを作ると【stories.pug】では、コンポーネントベースのコードで書くことが出来ます。
knobsまで作らなくても色々なパターンを作成しておけば、コピー用サンプルや見た目のテスト的な使用なども可能です。/stories/Components/LinkButton/サンプル.stories.puginclude LinkButton p +LinkButton({ }) | ノーマル p +LinkButton({ size:'small', color:'green', }) | 緑小 p +LinkButton({ size:'large', color:'gray', url:'https://google.com', isBlank:true }) | グレー大 p +LinkButton({ size:'small', full:true, })(class="addClass") | 小フルサイズknobsを書くJSのサンプル
今のコンポーネントをKnobs化するサンプルです。
/stories/Components/LinkButton/LinkButton.stories.jsimport { withKnobs, boolean, select ,text} from '@storybook/addon-knobs' import { renderer } from 'storypug' import LinkButton from './LinkButton.pug' const { html } = renderer() const sizes = { 'ノーマルボタン':'', '小さいボタン':'small', '大きいボタン':'large', } const colors = { 'デフォルト':'', 'グレー':'gray', 'グリーン':'green', } export default { title: 'Components/LinkButton', decorators: [withKnobs], } // knobs export const Knobs = () => html( LinkButton, { size: select('ボタンタイプ', sizes, sizes[0]), full: boolean('フルサイズ', false), color: select('色', colors, colors[0]), url: text('URL',''), isBlank: boolean('別窓', false), }, 'ボタンテキスト', ) Knobs.story = { parameters:{pugCode:'Components/LinkButton/LinkButton.pug'} }ビルドについて
githubpagesとテスト環境にそれぞれ作成したいというようなケースのために、ビルド設定を二つ用意しています。
- .storybook/default → 【npm run build】 元の設定と同様publicフォルダを設定しています。
- .storybook/second → 【npm run build2】 githubpagesを想定してdocsフォルダを設定しています。
.storybook/defaultをコピーしてpackage.jsonのscriptsを修正すれば、さらに複数作ることも可能です。
staticフォルダも元の設定と同様staticなのでメイン環境などと合わせる場合は、この辺も調整してください。ビルドにおけるpugの共通変数の設定
ファイルを置くパスが違うケースもあると思うので、それぞれの環境にpugの共通変数用としてpug-data.jsに変数をセットする仕組みを用意しています。
通常layout.pugなどに設定するような変数をここにセットすることで、コンポーネントを修正せずに出し分けすることができます。
【stories.pug】による自動追加でも、この共通変数が一緒にセットされます。pug-dataの使い方
先ほど作成したLinkButtonを使用して、外部リンク設定時にアイコンのimgタグを表示するように変更してみます。
1 画像フォルダの共通変数を設定
/.storybook/default/pug-data.js//pug common values module.exports = { imgDir:"/images/" }2 LinkButton.pugコンポーネントの【block】の下にblankのif文を追記
/stories/Components/LinkButton/LinkButton.puga.LinkButton(href=props.url)&attributes(attrs) block -if(props.isBlank) img(src=imgDir + 'icon-blank.png' width="16px" style="margin-left:10px")3 LinkButton.stories.jsの【renderer()】の行をpug-data.jsを読み込むように修正
/stories/Components/LinkButton/LinkButton.stories.jsimport pugData from '@conf/pug-data' const { html } = renderer(pugData)
- 投稿日:2020-02-26T15:23:47+09:00
javascriptでenvファイルを使う
javascriptでenvファイルを使う実装をまとめます。
前提条件
- npmがインストールされていること
インストール
npm
コマンドでモジュールをインストール$ npm i --save dotenv使い方
ファイルの作成
touch
コマンドでtest.js
ファイル、env
ファイルを作成$ touch test.js .envtest.js
require('dotenv').config() const { BASE_URL } = process.env console.log(BASE_URL).env
BASE_URL="http://localhost:8000/"実行
node
コマンドでtest.js
を実行するnode test
出力結果
http://localhost:8000/Nuxt.jsで使う場合
npm
コマンドでモジュールをインストール$ npm i --save @nuxtjs/dotenvnuxt.config.js
module.exports = { modules: [ '@nuxtjs/dotenv', // 追記 ] }参考文献
この記事は以下の情報を参考にして執筆しました。
- 投稿日:2020-02-26T15:21:50+09:00
GETとPOST
- 投稿日:2020-02-26T13:21:44+09:00
無限スクロールを実現する自作JQueryライブラリ loop.jsのご案内
はじめに
WebサイトのUXとして無限スクロールは既に一般的なUXとして採用されてきています。そこで制作してるサイトでもライブラリを用いて採用すると、思いのほか使い勝手が悪いことが判明し、ロジックを自作したものをライブラリとして公開するものです。このライブラリは下記の特徴(定義要件)の下で開発されたものです。
- 再読み込み時にもこれまでに読み込んだページがリセットされない
- 採用されたサイトにはフッターがあるためボタン操作で次のページが表示させる
- 100行前後の軽量なライブラリである
デモ・入手
このソースコードはGitHubから入手できます
https://github.com/emesh0620/jquery_loop_jsなお、デモは下記のページからご覧頂けます。
https://emesh0620.github.io/jquery_loop_js/実装
html部
まずループさせたい箇所に次のコードを入力します。
なお、next_loop_btm_bodyとnext_loopを変更する際にはソースコードを変更する必要があります。<div id = "next_loop"></div> <span id = "next_loop_btm_body"> <button id="next_loop_btm">もっと見る</button> </span>JS部
JavaScriptはたとえば次のコードになります。
<script type="text/javascript"> $(function() { //loop.jsの本体を呼び出す $('#next_loop_btm').loop_looping({ name : 'loop', url : 'loop/$.html', allpage : 2, }); //キャッシュをクリアしたい時に呼び出す $('#cache_clear').loop_looping_clear(); }); </script>
- name・・・HTMLのキャッシュ時に使う名前
- url・・・2ページ目以降のページを指示する注意点は下記の通りです。
- かならず表示順の連番として、HTMLであれば全て同一のディレクトリ入れること。
- 連番部分はJSに書き込む際には$で置換しておくこと。 (例えば loop/1.html loop/2.html...と続くなら loop/$.htmlとする)
- なお、HTMLを吐き出すことが出来れば動的サイトなどでも構わない。
- allpage・・・ループの総ページ数をかく。最初のページを入れた値を入れること。
キャッシュをクリアしたいときには適当な場所に、
$(任意のIDまたはClass).loop_looping_clear();
を挿入すればキャッシュはクリアされます。おわりに
このライブラリはMITライセンスにつき、ご利用の環境によってご自由に改変して頂いて結構です。例えば、キャッシュにはUNIXTimeを記録していますので一定の時間が経てばキャッシュをクリアするなどの使い方があります。
- 投稿日:2020-02-26T13:20:03+09:00
Preactの始め方&Reactとの違い
Reactのサブセットライブラリとして、Preactというものがあります。より軽量なReactという位置付けで、ダウンロードするjsファイルのサイズが肥大しがちなSPAサイトにおいて、パフォーマンスを向上させるための有効な選択肢の一つとして捉えられているようです。
使い方などを勉強してみたので、メモ代わりとしてPreactプロジェクトの始め方、Reactとの違いなどについてまとめておきます。
Reactとのサイズ差
PreactはReactより軽量ということですが、具体的にどのくらい違うのでしょうか?公式ドキュメントには3kB!!と書かれています。それではReactのライブラリサイズは...?ということで、「BUNDLE PHOBIA」というサイトで調べてみると、
- React: 6.4kB(minified), 2.6kB(minified & gzipped)
- Preact: 9.5kB(minified), 3.7kB(minified & gzipped)
あら...?Reactのほうが軽くない...?と一瞬思ってしまうのですが、ReactをWebで使うには、react-domも必要です。こいつのサイズを見てみると、
- react-dom: 114.6kB(minified), 36.2kB(minified & gzipped)
デカい!!Preactではreact-domは必要ないので、その分軽い、ということでしょうか。
Preactの始め方
Preactの公式ドキュメントに行くと、「Getting Started」というページがあり、その通りに進めればcreate-react-appに近い感じで簡単にプロジェクトをセットアップできます。
ただ、今回はその方法を使わずに手作業で必要なセットアップを行なっていきます。シンプルにするため、TypeScriptは導入しません。
まずは適当なディレクトリを作成し、npm initを入力。mkdir preact-sample npm init -yなにはともあれ、Preactをインストールします。
npm i --save preact
js, jsxファイルをバンドルするため、Webpack系のライブラリをインストール。
npm i --save-dev webpack webpack-cli webpack-dev-server
続けて、jsxファイルをトランスパイルするためのライブラリをインストール。
npm i --save-dev @babel/core @babel/preset-env babel-core babel-loader babel-preset-preact
.babelrcを作成します。
.babelrc{ "presets": [ "@babel/preset-env", "preact" ] }次に、webpack.config.jsを作成して設定を記述していきます。エントリポイントはsrc/index.jsx、バンドルファイルの出力先はdist/js/bundle.jsとします。
webpack.config.jsconst path = require("path"); const webpack = require("webpack"); module.exports = env => { return { entry: "./src/index.jsx", output: { filename: "./js/bundle.js" }, resolve: { extensions: [".js", ".jsx"] }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, use: ["babel-loader"] } ] }, devServer: { contentBase: path.join(__dirname, "./dist"), watchContentBase: true, } } }次にdistディレクトリを作って、その直下にindex.htmlを作成。
index.html<html> <head> <title>Preact sample</title> </head> <body> <div id="app"></div> <script src="./js/bundle.js"></script> </body> </html>最後にsrc/index.jsxに表示したいコンテンツを書けばOKです。
index.jsximport { h, render } from "preact"; const App = () => { return <div>Hello World!</div> }; render(<App />, document.getElementById("app"));これでwebpackのdevServerを立ち上げれば、Hello World!が表示されるはずです。あとは、普段Reactを書いているのとほぼ同じ感覚で進めていけます。関数コンポーネントやhooksも使えます。
ReactとPreactの違い
Reactとは何が違うのか、どういった機能が使えないのかが気になるところですが、それらは公式ドキュメントにまとめられています。(Differences to React)
そこまで分量も多くないので、自身で確認してみるのが一番良いと思います。Reactにあって、Preactにない機能の部分だけを抜粋します。
PropTypesによるバリデーションチェック
こういうのですね(以下のコードはReact公式ドキュメントからの抜粋です)。
import PropTypes from 'prop-types'; class Greeting extends React.Component { render() { return ( <h1>Hello, {this.props.name}</h1> ); } } Greeting.propTypes = { name: PropTypes.string };型チェックをするなら今ならTypeScriptを使うことが多いはずなので、なくてもとくに困らないような気はします。ちなみにPropTypesが必要なら、preact-compatというライブラリを入れることで補完できるようです。
React.Children
React.Childrenについての解説はこちら
props.childrenはよく使いますが、React.Childrenは使ったことがないですね。。。こちらもpreact-compatで補完できるとのことです。
Synthetic Events
Reactではイベントハンドラに渡されるイベントは全てラップされたものになっています。ラップされたイベントインスタンスは同じAPIインターフェースを持つので、ブラウザ間の差異を意識することなく、イベント処理を行えます。また、Synthetic Eventsインスタンスはプールされ、同じインスタンスが使い回されます。そのために、イベント処理が終了するとインスタンスの各フィールドが全てnullで初期化されるという特徴も持っています。
この仕様を知らずにハマった記憶もありますが、PreactではSynthetic Events機能は提供せず、ブラウザネイティブのイベントインスタンスがイベントハンドラに渡されるようです。これは知っておくべき違いな気がしますね。
まとめ
パッと調べた感じだと、Preactでよくない?と思えるのですが、他ライブラリとの互換性などの問題もあるのかもしれません。まずは小さいプロジェクトで試してみて、実際に使った場合にどんな問題が起こるのかを把握してから適切に使いたいですね。
- 投稿日:2020-02-26T13:06:32+09:00
npmコマンドの直列処理、並列処理の簡単な記述
npm
コマンドを簡単に記述して、直列処理、並列処理を行います。前提条件
- npmがインストールされていること
- package.jsonがあること
インストール
$ npm install -D npm-run-all使い方
設定
package.json
run-s
の後にコマンドを書くと直列、run-p
の後にコマンドを書くと並列で処理を行ってくれます。
コマンドをhello:*
と書くと、当てはまるすべてのコマンドを処理します。{ "scripts": { "hello:foo": "echo FOO", "hello:bar": "echo BAR", "hello-s": "run-s hello:foo hello:bar", "hello-p": "run-p hello:*" } }実行
npm
コマンドでhello-s
またはhello-p
を実行します。$ npm run hello-s
$ npm run hello-p
出力結果
FOO BAR参考文献
この記事は以下の情報を参考にして執筆しました。
- 投稿日:2020-02-26T12:28:26+09:00
JavaScriptで音声読み上げテスト
JavaScriptで音声読み上げのテストPGMを作成しました(空白を読み上げたい場合、'。'を記入)
参考にしたサイト
再生、一時停止、再開ボタン - Speech Synthesis APIgithubURL: https://github.com/NanjoMiyako/TextYomiageTest
サンプルページURL: https://nanjomiyako.github.io/TextYomiageTest/
- 投稿日:2020-02-26T12:24:24+09:00
PlayCanvas v1.25.0アップデート内容
PlayCanvasのアップデートについて
昨日PlayCanvas Engineがバージョン 1.24.7から 1.25.0にアップデートされました。このアップデートでは、WebXRのサポートの追加、examplesの追加、ドキュメントの修正、バッチングに対してのアップデートが入りました。
機能追加
WebXRサポート
こちらのコミットで
WebXR
のソースコードが追加されましたParticle System コンポーネントについて
こちらのコミットで
Particle texture atlas start frame property
のデモとソースコードが追加されましたこの変更により
Particle System
コンポーネントに対してanimStartFrame
のプロパティを追加できるようになりました。使ってみる
作成したプロジェクトはこちらです
https://playcanvas.com/project/667962/
このテクスチャをパーティクルとして使用する場合する際にanimStartFrame
を設定します。1. Particle Systemコンポーネントをを持つエンティティを作成する
b. Color Map, Normal Mapにテクスチャを追加
この画像を使用します
属性名 値 Color Map particles-numbers.png Normal Map particles-numbers.png c. 各種プロパティを設定
今回適用するテクスチャアトラスは4x4のものなのでそれに沿った設定をしていきます。
属性名 値 Horizontal Tiles 4 Vertical Tiles Tiles 4 2. animStartFrameを設定するParticleSystemコンポーネントを持つエンティティを4つ複製
3. animStartFrameを設定するスクリプトを追加
PlayCanvasのattributesを指定する方法でエディタから
animStartFrame
を設定できるようにします。/*jshint esversion: 6, asi: true, laxbreak: true*/ const Particle = pc.createScript('particle'); Particle.attributes.add("animStartFrame", {"type": "number"}) Particle.prototype.initialize = function() { this.entity.particlesystem.animStartFrame = this.animStartFrame };3.それぞれ値を設定する
それぞれのエンティティに対して、
animStartFrame
を設定します。エンテティ1
属性名 値 animStartFrame 0 エンテティ2
属性名 値 animStartFrame 4 エンテティ3
属性名 値 animStartFrame 8 エンテティ4
属性名 値 animStartFrame 12 実行する
実行をすると、パーティクルとして表示されているものがそれぞれ異なる位置から開始されました。
このスクリプトを設定したプロジェクトはこちら
https://playcanv.as/p/9bfxB3nU/GPU Instancing
こちらのコミットで
GPU Instancing
のデモとソースコードが追加されました。GPU Instancingについてはこちらの記事が参考になりました。
https://github.com/playcanvas/engine/commit/5f7c50102082cae250af8abf47d70b8636b1ccaaGPU Instancingは、複数の「同一メッシュ」かつ「同一マテリアル」なオブジェクトがあった場合に、GPU側で一括で描画してくれる技術みたいです。
http://tsubakit1.hateblo.jp/entry/2016/06/28/233000色々Examplesが追加
ARとVRのデモが多く追加されました。
※ 以上がv1.25.0のアップデート内容ですが、v1.25.1に今朝アップデートされていたのでそちらも追記致します
- 投稿日:2020-02-26T12:23:19+09:00
Promiseとasync/awaitの使い方
非同期で処理するためのPromise、async/awaitの基本的な使い方をまとめました。
詳しく知りたい方は参考文献をご確認ください。Promise
Promiseオブジェクトを返す
return new Promise((resolve, reject) => {})Promiseの結果を返す
resolveする
Promiseのresolveを実行する
return new Promise((resolve, reject) => { resolve('成功です') })rejectする
Promiseのrejectを実行する
return new Promise((resolve, reject) => { reject('失敗です') })async/await
処理の結果を待つ
async function sample() { const result = await samplePromise() console.log(result.data) }並列で処理する
async function sample() { const array =[5, 10, 15] const promiseAll = await Promise.all( array.map(async (value) => { return await samplePromise(value) }) ) return promiseAll }例外処理(エラーハンドリング)
async function errorHandling() { try { const result = await throwError() return result } catch (err) { throw err } }参考文献
この記事は以下の情報を参考にして執筆しました。
- 投稿日:2020-02-26T12:14:57+09:00
【Tesseract.js】ブラウザだけで画像内の文字を解析
Tesseract.jsは、画像解析ができるJavaScriptライブラリです。画像に書かれた文章を文字列に起こしてくれます。
最近使う機会があってなかなか良かったので、布教も兼ねてすぐに試せるコードをいくつか紹介します。
変更してみて欲しい箇所にはコード内にコメントしています。ライブラリの基本的な使用法については公式ドキュメントや他の記事で紹介されているので、そちらを参照ください。
画像例
この例ではLorem ipsumを解析します。
意味のない文章なので解析しづらいと思いますが、頑張ってもらいましょう。
1枚丸ごと解析
1枚の画像をブラウザに添付し、書いてある文字をすべて解析する例です。
以下のCDN使用例はhtmlファイルにコピペで動きます。
言語によって解析精度はかなり変わってくるので、色々な言語の画像で試してみてください。
…しかしLorem ipsumって何語で解析すれば良いんでしょうかね?元々意味がない文章とのことなので、ここでは日本語で進めます。<html lang="ja"> <body> <input type="file" id="image_zone"> <div id="output"></div> <script src='https://unpkg.com/tesseract.js@v2.0.2/dist/tesseract.min.js'></script> <script> const imageZone = document.getElementById('image_zone') imageZone.addEventListener('change', resizePinnedImage, false) function resizePinnedImage(e) { const file = e.target.files[0] if (!file.type.match('image.*')) { return } Tesseract.recognize( file, 'jpn', // 言語設定 { logger: m => console.log(m) } ).then(({ data: { text } }) => { const out = document.getElementById('output') out.innerHTML = text }) } </script> </body> </html>結果は以下のようになりました。
文字が繋がってしまっているので、画像を拡大したほうがよさそうです。次でやってみましょう。Loem ipaundoorstamet coreeaeuradpscng eltseddoeuanod ierpornddguntutkkov etdoo magnaalqua_uienmad mimvenam qusrowud clatonulanco mboisneiuaiqdpexea commodocomsequat Dus aue ue coornrepeherdet Invoupaaeveltessoclun ooe eugdatnulaparauc cepeursntocuccatopdaatronpoden smtncupaquoWca desenntmottammigestkboum Cuablurpetuntndduniacus Nulagavdaociaodo_Nulanvaus upsqtcommodorhaevacaecsbbendunclrec MNcus magafal solgudn maus neoernmautseunbneuenodgevda Dusecteusotausvpuaevencua ponec kbots iusaelt lanterporUtulancopec leua cutenporcorgue wosesteuenoduupsidtnddunsapenrsusaquan Maccenasfermenun consequatn Doneciermenun Palencwaue maesuadanulaaml Dussanensen aiqetnec ommodo 0eb coreoquatqusyneque Aiquan eucbus gltutdcunaiguet elsnsiadpscngsapen sod naesuade danacuscoatem as molsscacisquenune Nlanacu_Alquam oonscqua Cusburaugueloemdapbusqus loeetat petunacnet Amneanmagnansl roNsqus nocsie cu_eugatinocLinhachabtasepaeadcuns、
画像を拡大して解析
以下はキャンバスを利用して画像を2倍に拡大して解析する例です。
Tesseractの対応形式は広く、Canvas要素をそのまま投入可能なのも便利なところです。<html lang="ja"> <body> <input type="file" id="image_zone"> <br> <canvas id="canvas"></canvas> <div id="output"></div> <script src='https://unpkg.com/tesseract.js@v2.0.2/dist/tesseract.min.js'></script> <script> const imageZone = document.getElementById('image_zone') imageZone.addEventListener('change', resizePinnedImage, false) function resizePinnedImage(e) { const file = e.target.files[0] if (!file.type.match('image.*')) { return } resize(file) } function resize(file) { imageToCanvas(file).then(function (canvas) { Tesseract.recognize( canvas, // Canvasを投げられる! 'jpn', { logger: m => console.log(m) } ).then(({ data: { text } }) => { const out = document.getElementById('output') out.innerHTML = text }) }).catch(function (error) { console.error(error) }) } function imageToCanvas (imageFile) { return new Promise(function (resolve, reject) { readImage(imageFile).then(function (src) { loadImage(src).then(function (image) { const canvas = document.getElementById("canvas") const ctx = canvas.getContext('2d') // スケール2倍 const scale = 2 canvas.width = image.width * scale canvas.height = image.height * scale ctx.drawImage( image, (image.width - (canvas.width / scale)) / 2, (image.height - (canvas.height / scale)) / 2, canvas.width / scale, canvas.height / scale, 0, 0, canvas.width, canvas.height ) resolve(canvas) }).catch(function (error) { reject(error) }) }).catch(function (error) { reject(error) }) }) } function readImage(image) { return new Promise(function (resolve, reject) { const reader = new FileReader() reader.onload = function () { resolve(reader.result) } reader.onerror = function (e) { reject(e) } reader.readAsDataURL(image) }) } function loadImage(src) { return new Promise(function (resolve, reject) { const img = new Image() img.onload = function () { resolve(img) } img.onerror = function (e) { reject(e) } img.src = src }) } </script> </body> </html>この例では、拡大後の画像がキャンバスに表示されます。(大きすぎるのでトリミングしました)
そして解析結果は以下のようになりました。
sやuの大文字・小文字違いを除けばほとんどが正確で、やはりちょうどよい文字の大きさがあるようです。Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cUpidatat non proident, SUunt in culpa qui officia deserunt mollit anim id est laborum. Curabitur pretium tincidunt lacus. Nulla gravida orci a odio. Nullam varius, turpis et commodo pharetra, est eros bibendum elit, nec luctus magna felis sollicitudin mauris. Integer in mauris eu nibh euismod gravida. Duis ac tellus et risus vulputate vehicula. Donec lobortis risus a elit. Etiam tempor. Ut ullamcorper, ligula eu tempor congue, eros est eUuismod turpis, id tincidunt sapien risus a dquam. Maecenas fermentum consequat mi. Donec fermentum. Pellentesque malesuada nulla a mi. Duis sapien sem, aliquet nec, commodo edet, consedquat quis, neque. Aliquam faucibus, elit ut dictum aliquet, felis nisl adipiscing sapien, sed malesuada diam lacus eget erat. Cras mollis scelerisque nunc. Nullam arcu. Aliquam consedquat. Curabitur augue lorem, dapibus quis, laoreet et, pretium ac, nisi Aenean magna nisl, mollis quis, molestie eu, feugliat in, orci. In hac habitasse platea dictumst.
画像の一部を切り取って解析
先ほどとほぼ同じですが、画像の真ん中を(この例では
200px * 100px
)切り取って解析する例です。
画像の必要のない部分をカットすることで、高速な解析が望めます。<html lang="ja"> <body> <input type="file" id="image_zone"> <br> <canvas id="canvas"></canvas> <div id="output"></div> <script src='https://unpkg.com/tesseract.js@v2.0.2/dist/tesseract.min.js'></script> <script> const imageZone = document.getElementById('image_zone') imageZone.addEventListener('change', resizePinnedImage, false) function resizePinnedImage(e) { const file = e.target.files[0] if (!file.type.match('image.*')) { return } resize(file) } function resize(file) { imageToCanvas(file).then(function (canvas) { Tesseract.recognize( canvas, 'jpn', { logger: m => console.log(m) } ).then(({ data: { text } }) => { const out = document.getElementById('output') out.innerHTML = text }) }).catch(function (error) { console.error(error) }) } function imageToCanvas (imageFile) { return new Promise(function (resolve, reject) { readImage(imageFile).then(function (src) { loadImage(src).then(function (image) { const canvas = document.getElementById("canvas") const ctx = canvas.getContext('2d') // 幅200、高さ100 width = 200 height = 100 canvas.width = width canvas.height = height ctx.drawImage(image, (image.width / 2) - width / 2, (image.height / 2) + height / 2, width, height, 0, 0, width, height) resolve(canvas) }).catch(function (error) { reject(error) }) }).catch(function (error) { reject(error) }) }) } function readImage(image) { return new Promise(function (resolve, reject) { const reader = new FileReader() reader.onload = function () { resolve(reader.result) } reader.onerror = function (e) { reject(e) } reader.readAsDataURL(image) }) } function loadImage(src) { return new Promise(function (resolve, reject) { const img = new Image() img.onload = function () { resolve(img) } img.onerror = function (e) { reject(e) } img.src = src }) } </script> </body> </html>雑に切り取ったら変なことになってしまいました。
個人的にはアプリ画面の必要な部分だけを切り取る用途に使う予定です。
以上です。ぜひ遊んでみてください。
- 投稿日:2020-02-26T11:41:18+09:00
脱・AtomicDesign - HTML+CSSコーディングの粒度分類法(HTML Parts)
はじめに
HTML+CSSコーディング専用の粒度分類を紹介します。
この仕組みは、デザインやワイヤーフレームなどの視覚情報を分解することに焦点をあて、分解した対象を部品化する流れも併せてガイド化した汎用手法です。
世の中には、コーポレートサイト / ポータルサイト / サービスサイト / システム管理画面 / ブログサイト… といった様々な種別のサイト、Webページがありますが、これらの「完成予想図(視覚情報)」を同じ方法で分解して、コーディング用の部品にできます。粒度と言えばAtomicDesignが有名ですが、この「HTML Parts」も粒度そのものの考え方についてはAtomicDesignの踏襲です。その上で「思考の入り方・捉え方」や「名称と定義」をコーディング側に寄せることで、CSS設計やコーディング業務を標準化しやすくしています。
※この記事は標準化ノウハウ公開の一環として書いています。
仕組みの概要や前提事項などについては「UltimateCoding 概要・前提事項」のエントリをご確認ください。前置きとAtomicDesign
そもそもAtomicDesignをコーディング視点で評するのはお角違いかもしれませんが、業界の一部では"万能薬"として組み入れる試みがあったのも事実です。それほど、画期的かつ魅力的な概念でした。主題に入るまえに「なぜ万能になり得なかったのか」を簡単に箇条書きします。
- 小さなものから積み上げていく概念と、多くのコーディングで必要となる分解の行動が相反する
- TemplatesとPagesが別の意味を喚起してしまい、そのままコーディングに使うと混乱する
- サイト種別や規模によっては、図のA側に欲しい粒度が一つ不足することがある
といった所でしょうか。良い解決方法があるかのもしれませんが「そのままの状態で万能か?」と言われたら、そうではないでしょう。これは、AtomicDesignが不出来といいたいのではなく、専用に作られていないものを転用して使おうとしても、やはりどこか無理が出てくる。というお話です。
HTML Partsの概要
では、本題の「コーディング側から考える粒度分類」の話です。
HTML Partsは、以下のようにデザインやワイヤーフレームを「大きなものから小さなものへと分解」する事で粒度を分類します。
この方法は、改めて言われなくとも既に多くの制作者が自然とおこなっているであろう流れ・ステップです。こういった一般的な流れの上にガイドを沿えることで、思考による変換や再構築を発生させず、負担がかかりにくいものとして提起します。また、これがもしAtomicDesignによって「システマチックに作られたプロダクト」であったとしても、同じように上から綺麗に分解できることでしょう。
実用の見通しと説明内容
粒度の概念を実際のコーディングに実用するためには、以下の3つの内容把握と、Sassファイル管理の仕組みが必要となります。
- 視覚情報の分解方法 を把握
- 部品再利用設計の考え方 を把握
- 粒度の定義 を把握
以降、上記の順に従って説明します。
Sassファイルの管理方法については、最後に要点を述べた上で、今後別の記事で詳しく説明します。1 ・ 視覚情報の分解方法
まず1つめの、具体的にどのように分解するのかについての説明です。
方法はいたってシンプルで、分解する対象である「完成予想図」を用意し、以下の図のように大きなものから4つの粒度によって分解していきます。
図は企業系サイトを例にしていますが、サービス系サイト、ポータル系、システム管理画面、LP、ブログなど、どんな種別であっても「Webページの視覚情報」がある限り、分解手順そのものは同じです。また、上記の図と、この記事の情報は、過去記事「1段上のCSS設計・コーディングの概念図」の内容と連動しています。この記事を単独で読んでも意味は通じますが、より良く利用したい場合には併せてご覧下さい。
図との対応としては、左の2つの概念を実用するためのガイドが「HTML Parts」です。「Block」が今回のBlockと等価で、「Parts」が、今回のModule / Component / Elementに細分類されます。2 ・ 部品再利用設計の考え方
粒度の具体的な説明に移る前に、重要な考え方・ポイントを先に説明します。
何かというと「粒度分類と実装は別で考える」という事です。ここを一緒にして捉えると後で混乱のもとになるため、先に2つの意味を説明します。1 ・分類は必ず発生している
まず、分類そのものは常に発生しています。どういうことかというと、仮に、デザインやワイヤーフレームを紙に印刷して、ペンで四角い線を引いて分解しながら囲っていったとします。もうこれ以上分解できない。という所まで線をひくと、実質、紙の上に全ての粒度が洗い出されたことになります。
そして、特定の部分を見て、「AtomicDesignではこれはAtomsと呼ばれている」とか、今回の「HTML PartsであればElementと呼ばれている」というように、変わりようのない定義・事実として認識できます。これが、分類は必ず発生している。という意味です。そして、この時点では実装に関する決めごとは何も発生していません。決める(設計する)のは制作者です。
2 ・どのように部品化するのか
次に、部品をどのようなコードで実装するか。という話です。
判断・意思決定するのは1つだけ。「その対象(部品)を、グローバルに再利用するかどうか」です。これが、CSS設計が大きく切り替わるポイントとなります。「グローバルに再利用する」とは、以下のようなものです。
これは、CSS設計手法の「OOCSS」と同じ方向にある手法で、システム管理画面やサービス系サイトなどの「システマチックなサイト」で利用したくなるものです。もし、上記のように再利用しないのであれば、その部品は以下のように「上位粒度の所有物」としてスタイリングします。
これらの図をテキストでまとめると以下のようになります。
- 1・単体でグローバルに再利用できるCSSを書く
- 図:スタイリングパターンA
- 2・上位粒度の所有物となるCSSを書く
- 図:スタイリングパターンB
- 図:スタイリングパターンC
そして、これらを「サイト全体視点」と「部品単独視点」の2つの軸で判断していくことが、「CSS設計」の中核であり重要ポイントになります。
これらの前提を踏まえた上で、以下から粒度の説明をおこないます。
3 ・ 粒度の定義把握
各粒度の詳細説明です。
それぞれに細かな定義や判断基準などを記載していますが、先述の通り「粒度分類と実装は別」であり、これらはあくまで制作のためのガイドです。制作者の判断以上に強い立場ではありません。レギュレーションによって「完全遵守・例外は認めない」と定めるなら話は別ですが、そうではないなら「その視覚情報をどのようにコード管理したいのか」という、制作者の意思・意図を優先し、"ねばならない"の思考に捕らわれることがないようご注意下さい。
1 ・ Block
Block(ブロック)は、情報の意味や役割的に自立・独立した領域や区画・塊です。
機能・役割・情報属性などの基準によって、制作者が「これ以上は他と同じにできない」と判断した範囲によって切り出します。多くの場合は
div
によるコンテナに名前が与えられます。Blockの粒度判断
粒度の判断は、主たる情報である「コンテンツ」と、ヘッダー・フッターなどの「フレーム」部分とで分けて考えることができます。具体的には以下のようになります。
- コンテンツ
article
section
aside
といったタグでマークアップできそうな範囲- 見出しに使う
h
タグを含むもの(文書上の暗示・省略されたものも含む)- 任意の構造体が入りそうなもの
- フレーム
- ルートの
header
main
footer
や、nav
の領域また、これらは、プロジェクトやデザインの文脈によって解釈が異なるというのはあり得る話です。
例えば、同じブランディングエリアであっても、ヘッダーバーの中に小さくあるものと、ブラウザ全面に画像や動画が敷かれ、数点のリンクと共に中央に配されるようなブランディングエリアとでは解釈・役割が異なるでしょう。Blockの部品作成方法
block/
にSassファイルとして切り出してCSSを管理します。
もし、Blockの内部部品に「下位粒度のグローバルな再利用部品」(スタイリングパターンAで作られた部品)を設置する場合は、Blockはそれらの部品を設置するための枠組みのような役割にとどまるでしょう。
逆に、Block内部の部品を自分の一部としてスタイリングする場合は、先述のスタイリングパターンB・Cどちらかでスタイリングすることになります。Blockのユースケース
コーポレートやブログ、ブランディング、LPなどの情報発信系サイトであれば、よほどの規模ではない限り、この分類でコード化は完成するのではないかと思います。
内部部品はスタイリングパターンB/C(※近年の慣例手法はCのBEM式)のみで作成し、同じ部品が何度か登場したとしても、パターンAの代わりに、SassのExtendやMixin機能で同一コードを流用して完成させるような方法です。参考情報
余談・参考情報になりますが、
body
タグ直下に機能的・慣例的に設置する.wrapper
といった命名の「全体包括要素」もBlockであると捉えると、「Block同士は恒常的にネストする」という意味が理解しやすくなります。※このとき、思考のつじつまが合いやすい命名は.site
です。<body> <div class="site"><!--この中にあるのは「サイト」の表示用データ--> <div class="site-header"> <header>…</header> </div> <div class="site-main"> <main>…</main> </div> <div class="site-footer"> <footer>…</footer> </div> </div> </body>また、コンテンツのBlockも同じ構造を意識してマークアップすることで、サイト全体のコードがフラクタル構造(自己相似)となり、ルールが捉えやすくなります。(※サンプルはBEM記法で記載)
<div class="photo-gallery"><!--この中にあるのは「写真ギャラリー」表示用のデータ--> <section> <div class="photo-gallery__header"> <header>…</header> </div> <div class="photo-gallery__body"> … </div> <div class="photo-gallery__footer"> <footer>…</footer> </div> </section> </div>2 ・ Module
Module(モジュール)は、単体でも機能しそうな中程度の情報の塊です。
カードや、ギャラリーの1区画。会員証を模したようなもの、プロフィールのひと塊、ECサイトの商品一覧、メニューナビゲーションの1区画などが該当するでしょう。多くの場合は
div
によるコンテナに名前が与えられます。Moduleの粒度判断
粒度の判断は、コンテンツ部分とフレーム部分で分けて考えられます。
下位粒度のcomponentが集まったものと捉えるとイメージしやすいかもしれません。
- コンテンツ
- Blockほどの情報の規模感は無いが、単独でも機能しそうな視覚情報の塊
- 場合によっては任意の構造体が入りそうなもの
- その場でリピートして使われそうなもの
- フレーム
- ブランディングエリアや、コンタクト情報 等
- ブランディングエリアや、サイトマップリンク、コンタクト情報 等
Moduleの部品作成方法
自身をグローバルな再利用部品として管理したい時に、
module/
ディレクトリに切り出して管理します。そうではないなら、この粒度のものは、上位粒度の持ち物としてスタイリングが完了しているはずです。Moduleのユースケース/この粒度は必要か
ModuleはBlockと近い存在となります。特にBEM記法を使っているとBEMのBlockの概念と相まって「粒度が違えば全てModuleディレクトリに切り出さないといけないのか?」となる事もあるでしょう。そういった管理が煩雑になる場合は、Blockとして管理しても何も問題ありません。(究極は、制作者が混乱しなければよいのです)
では、定義の意味は?
「であれば結局は無法地帯では?」と思われるかもしれませんが、そうではありません。どんな時にこの粒度が有用かというと、1つは再利用の明示です。
Blockは最上位にあるため、どのように再利用しているのか、もしくはしていないのかはHTMLファイルを要調査。となりますが、Moduleディレクトリに置いただけで「どこかで必ず再利用されている中粒度部品」もしくは「どこで再利用してもよい中粒度部品」として意識づけできます。
最初にBlockのディレクトリにSassファイルを置いていても、後から上記のように明示したくなった場合は移動させることもできます。システム開発との連動
もう1つ有用なパターンは、ECサイトやサービスサイトなどのシステムが絡む時です。
システム側のフロントテンプレートなどにおいて「モジュール」として切り出すものは、この粒度と同じ規模感になるものも多くあります。それぞれ同じModuleという名称のディレクトリで管理すれば、双方が意識上対応したものとして管理できます。このように、実用時には必要に応じて使い分けられる粒度となります。
3 ・ Component
Component(コンポーネント)とは、見出しやボタン、リストや表組などの、単体でもその部品の機能や目的・情報が分かる小さな要素です。
ModuleやBlockから見れば、自分達を構成する小さな部品群で、下位粒度のElementのから見た時には、Elementの組み合わせがComponentであると表現できます。この粒度のものには「構造体」や「文書構造」が入ることはありません。
div
やspan
のラッパーに名前を与えることもあれば、ul
ol
table
などに名前を与えることもあるでしょう。Componentの粒度判断
文書構造や構造体が入る余地・感覚が無いもので、かつ、以下の1~4のうち、1つでも当てはまればComponentとなります。
- 視覚情報
- 1・視覚情報として分割できる
- HTMLコード
- 2・HTMLタグがHTMLタグでラップされている
- 3・内部を自然に拡張できる
- 4・コードとして分割・分離できる
また、レンダリング結果はElementと同一になるが、コード側から見ればComponentと判断できるものがあります。以下のようなパターンです。
コード側から見てComponentになる例
img
タグ単体は後述するElementにあたりますが、これを<div class="image">
などでラップすれば、.image
は立派なComponentです。「分解・分離できる状態」であり、後に内部にキャプションを入れるなど、「自然に拡張できる状態」になっています。同様に、
p
タグだけの文章はElementの粒度にあたりますが、これを<div class="text_box">
といったような命名のボックスでラップすれば、同様にComponentとなります。文章が追加されても、新たなp
タグによって内部を自然と拡張できます。Componentの部品作成方法
自身をグローバルな再利用部品としたい場合に、
component/
ディレクトリに切り出して管理します。そうではないなら、この粒度のものは、上位粒度の持ち物としてスタイリングが完了しているはずです。Componentのユースケース
Componentをグローバルな再利用部品として作成・運用したくなるのは、システム管理画面やシングルアプリケーション系のプロダクト、ブログの記事内の部品、サービスサイトのUI部品などでしょう。
OOCSSの概念と併用する事が多くなるでしょうし、"既製品"としてBootstrapのようなCSSフレームワークを利用する事になるのかもしれません。小規模でシステマチックではない静的サイトであれば、Blockの項に記載したとおり、Componentは全て上位粒度の持ち物としてスタイリングした方が効率よく管理できるでしょう。
部品の集まりをどう捉えるか
この粒度のものは、幾つかの部品が集まり特定の機能になる場合もあります。例えば、ボタンが複数横に並んで連結されていれるような場合です。これはComponentの集まりである。と捉える事もできますし、
div
でラップして「ナビゲーション」という意味の名前を与えればModuleにも、Blockにもできます。
つまり、そのプロジェクトにおいて、対象の部品をどのように管理したいか。という制作者の意思・意図が第一優先です。それをサポートするように、振り分けできる手立てが用意されている。という事になります。参考情報
Componentは特性として2つの属性のものがあります。
1つは、テーブル(table)やリスト(ul,ol,dl)など、HTMLの仕様により内部構造が定められているものです。これらは、HTMLの仕様に従い内部を拡張できますが、使えるタグは限られています。もう1つは、「アイコン+タイトル=メニュー項目」「ラジオボタン+テキスト=選択部品」とするなど、制作者の意図により小さな部品を組み合わせてComponentとしたものです。
※この区分けは粒度分類には影響しません。属性的に2つのものがあるという参考情報です。
4 ・ Element
Element(エレメント)は、表示上の面積に関わらず、視覚情報上もしくはコード上でもそれ以上部品分解できない最小の要素です。
Elementの組み合わせ、もしくは単体を何らかの要素でラップすれば、Componentとなります。
img
やinput
など、直接レンダリングされるタグやspan
、i
などに名前を与える事があるでしょう。Elementの粒度判断
それ以上分割分割できない要素で、一行のテキストや、ラジオボタン、チェックボックスなどです。無理に分割しようとすると、意図した情報伝達ができない、機能不全になる、コードとして成立しないといった不都合が起きるようなものが該当します。
また、粒度はレンダリング時の面積にとは関係がありません。いくら面積の広い画像を配置しようとも、img
タグレベルは一様にElementの粒度となります。どれだけ巨大なアイコンや、ラジオボタンを配置したとしても同じ事が言えます。Elementの部品作成
自身をグローバルな再利用部品としたい場合に、
element/
ディレクトリに切り出して管理します。そうではないなら、この粒度のものは、上位粒度の持ち物としてスタイリングが完了しているはずです。Elementのユースケース
この粒度をグローバルな再利用部品として作成・運用するとなると、独自にCSSフレームワークを作る。もしくは、ドラッグ&ドロップでサイトを作っていくようなサービスを構築する時でしょうか。※他にも用途はあるかもしれません
その他
プレフィックス
実用する際には、これらに名前を与えてからCSSプロパティを書くことになりますが、命名時のプレフィックスのルールはここでは定めません。(ガイドという立場として、特に奨励も制限もしません)
制作の必要性に応じて「再利用前提のものはm-
c-
e-
を付与する」など、それぞれ使い勝手が良いように自由にルールを制定してください。アイデア
これはまだ試せていませんが、1つのアイデアとして、この粒度分類を逆にデザインシステム側に反映できるかもしれません。コーディング側で最適化したものをデザインシステムに乗せられたなら、スムーズに連携できる可能性はあります。
粒度の総括
以上、4つの粒度をコーディングの側面から定義しました。
分類そのものの本質部分を見ればAtomicDesignのそれと非常に近いものですが、思考の入り方と語句の定義を変えただけで、人の認識や使用感は異なったものになります。
では、これが万人向けするのか。といえば、それは分かりません。しかし、少なくとも1つの組織と協力会社において使用する限り、破綻などの問題がゼロであることは事実です。HCDCモデル図と今回の「HTML Parts」、そして、次回公開する「Sassファイルディレクトリ管理手法」によって、より多くのサイト種別に対応した設計がおこないやすくなります。
Sassファイル・ディレクトリ管理
これらの粒度の名称は、そのままSassファイル管理ディレクトリの名称として利用することになります。
部品化の方法としては、先述の通り「グローバルに再利用する場合」のみ、その粒度のディレクトリに部品を切り出して管理します。しかし、これらを含めた全体をどのように管理するかは、また別の話となります。これはCSS設計の命題のひとつであり、概念を実務利用するための重要事項となります。
次回紹介するものは、プロジェクトごとにカスタマイズ可能なSassファイル管理の仕組みです。標準ルールを中心として、同じロジックでいくつものサイトタイプに柔軟に対応できます。この記事作成時点での実務利用実績は以下の通りです。
コーポレートサイト / ポータルサイト / サービスサイト / システム管理画面 / ブログサイト / ECサイト(オンラインショップ) / ランディングページ(LP) / イントラサイトこの管理方法についての情報は、投稿次第こちらの記事からもリンクします。
関連記事
クレジット・その他
Ultimate Coding
概要・前提事項
- 設計・考案/構築/記事投稿
- @croco_works - Twitter
- 設計パートナー/技術検証
- @wildwest_kazya - Twitter
この仕組みは、組織所属時に業務効率化のために構築したものであり、許可を得た上で設計者本人が個人活動として公開しています。商用の制作や開発には利用していただけますが、仕組みを販売したり媒体化するなどの、制作以外での商用化はご遠慮下さい。質問その他、何かあれば@croco_worksまでお声かけください。
- 投稿日:2020-02-26T11:41:18+09:00
脱・Atomic Design - HTML+CSSコーディングの粒度分類法(HTML Parts)
はじめに
HTML+CSSコーディング専用の粒度分類を紹介します。
この仕組みは、デザインやワイヤーフレームなどの視覚情報を分解することに焦点をあて、分解した対象を部品化する流れも併せてガイド化した汎用手法です。
世の中には、コーポレートサイト / ポータルサイト / サービスサイト / システム管理画面 / ブログサイト… といった様々な種別のサイト、Webページがありますが、これらの「完成予想図(視覚情報)」を同じ方法で分解して、コーディング用の部品にできます。粒度と言えばAtomic Designが有名ですが、この「HTML Parts」も粒度そのものの考え方についてはAtomic Designの踏襲です。その上で「思考の入り方・捉え方」や「名称と定義」をコーディング側に寄せることで、CSS設計やコーディング業務を標準化しやすくしています。
※この記事は標準化ノウハウ公開の一環として書いています。
仕組みの概要や前提事項などについては「UltimateCoding 概要・前提事項」のエントリをご確認ください。前置きとAtomic Design
そもそもAtomic Designをコーディング視点で評するのはお角違いかもしれませんが、業界の一部では"万能薬"として組み入れる試みがあったのも事実です。それほど、画期的かつ魅力的な概念でした。主題に入るまえに「なぜ万能になり得なかったのか」を簡単に箇条書きします。
- 小さなものから積み上げていく概念と、多くのコーディングで必要となる分解の行動が相反する
- TemplatesとPagesが別の意味を喚起してしまい、そのままコーディングに使うと混乱する
- サイト種別や規模によっては、図のA側に欲しい粒度が一つ不足することがある
といった所でしょうか。良い解決方法があるかのもしれませんが「そのままの状態で万能か?」と言われたら、そうではないでしょう。これは、Atomic Designが不出来といいたいのではなく、専用に作られていないものを転用して使おうとしても、やはりどこか無理が出てくる。というお話です。
HTML Partsの概要
では、本題の「コーディング側から考える粒度分類」の話です。
HTML Partsは、以下のようにデザインやワイヤーフレームを「大きなものから小さなものへと分解」する事で粒度を分類します。
この方法は、改めて言われなくとも既に多くの制作者が自然とおこなっているであろう流れ・ステップです。こういった一般的な流れの上にガイドを沿えることで、思考による変換や再構築を発生させず、負担がかかりにくいものとして提起します。また、これがもしAtomic Designによって「システマチックに作られたプロダクト」であったとしても、同じように上から綺麗に分解できることでしょう。
実用の見通しと説明内容
粒度の概念を実際のコーディングに実用するためには、以下の3つの内容把握と、Sassファイル管理の仕組みが必要となります。
- 視覚情報の分解方法 を把握
- 部品再利用設計の考え方 を把握
- 粒度の定義 を把握
以降、上記の順に従って説明します。
Sassファイルの管理方法については、最後に要点を述べた上で、今後別の記事で詳しく説明します。1 ・ 視覚情報の分解方法
まず1つめの、具体的にどのように分解するのかについての説明です。
方法はいたってシンプルで、分解する対象である「完成予想図」を用意し、以下の図のように大きなものから4つの粒度によって分解していきます。
図は企業系サイトを例にしていますが、サービス系サイト、ポータル系、システム管理画面、LP、ブログなど、どんな種別であっても「Webページの視覚情報」がある限り、分解手順そのものは同じです。また、上記の図と、この記事の情報は、過去記事「1段上のCSS設計・コーディングの概念図」の内容と連動しています。この記事を単独で読んでも意味は通じますが、より良く利用したい場合には併せてご覧下さい。
図との対応としては、左の2つの概念を実用するためのガイドが「HTML Parts」です。「Block」が今回のBlockと等価で、「Parts」が、今回のModule / Component / Elementに細分類されます。2 ・ 部品再利用設計の考え方
粒度の具体的な説明に移る前に、重要な考え方・ポイントを先に説明します。
何かというと「粒度分類と実装は別で考える」という事です。ここを一緒にして捉えると後で混乱のもとになるため、先に2つの意味を説明します。1 ・分類は必ず発生している
まず、分類そのものは常に発生しています。どういうことかというと、仮に、デザインやワイヤーフレームを紙に印刷して、ペンで四角い線を引いて分解しながら囲っていったとします。もうこれ以上分解できない。という所まで線をひくと、実質、紙の上に全ての粒度が洗い出されたことになります。
そして、特定の部分を見て、「AtomicDesignではこれはAtomsと呼ばれている」とか、今回の「HTML PartsであればElementと呼ばれている」というように、変わりようのない定義・事実として認識できます。これが、分類は必ず発生している。という意味です。そして、この時点では実装に関する決めごとは何も発生していません。決める(設計する)のは制作者です。
2 ・どのように部品化するのか
次に、部品をどのようなコードで実装するか。という話です。
判断・意思決定するのは1つだけ。「その対象(部品)を、グローバルに再利用するかどうか」です。これが、CSS設計が大きく切り替わるポイントとなります。「グローバルに再利用する」とは、以下のようなものです。
これは、CSS設計手法の「OOCSS」と同じ方向にある手法で、システム管理画面やサービス系サイトなどの「システマチックなサイト」で利用したくなるものです。もし、上記のように再利用しないのであれば、その部品は以下のように「上位粒度の所有物」としてスタイリングします。
これらの図をテキストでまとめると以下のようになります。
- 1・単体でグローバルに再利用できるCSSを書く
- 図:スタイリングパターンA
- 2・上位粒度の所有物となるCSSを書く
- 図:スタイリングパターンB
- 図:スタイリングパターンC
そして、これらを「サイト全体視点」と「部品単独視点」の2つの軸で判断していくことが、「CSS設計」の中核であり重要ポイントになります。
これらの前提を踏まえた上で、以下から粒度の説明をおこないます。
3 ・ 粒度の定義把握
各粒度の詳細説明です。
それぞれに細かな定義や判断基準などを記載していますが、先述の通り「粒度分類と実装は別」であり、これらはあくまで制作のためのガイドです。制作者の判断以上に強い立場ではありません。レギュレーションによって「完全遵守・例外は認めない」と定めるなら話は別ですが、そうではないなら「その視覚情報をどのようにコード管理したいのか」という、制作者の意思・意図を優先し、"ねばならない"の思考に捕らわれることがないようご注意下さい。
1 ・ Block
Block(ブロック)は、情報の意味や役割的に自立・独立した領域や区画・塊です。
機能・役割・情報属性などの基準によって、制作者が「これ以上は他と同じにできない」と判断した範囲によって切り出します。多くの場合は
div
によるコンテナに名前が与えられます。Blockの粒度判断
粒度の判断は、主たる情報である「コンテンツ」と、ヘッダー・フッターなどの「フレーム」部分とで分けて考えることができます。具体的には以下のようになります。
- コンテンツ
article
section
aside
といったタグでマークアップできそうな範囲- 見出しに使う
h
タグを含むもの(文書上の暗示・省略されたものも含む)- 任意の構造体が入りそうなもの
- フレーム
- ルートの
header
main
footer
や、nav
の領域また、これらは、プロジェクトやデザインの文脈によって解釈が異なるというのはあり得る話です。
例えば、同じブランディングエリアであっても、ヘッダーバーの中に小さくあるものと、ブラウザ全面に画像や動画が敷かれ、数点のリンクと共に中央に配されるようなブランディングエリアとでは解釈・役割が異なるでしょう。Blockの部品作成方法
block/
にSassファイルとして切り出してCSSを管理します。
もし、Blockの内部部品に「下位粒度のグローバルな再利用部品」(スタイリングパターンAで作られた部品)を設置する場合は、Blockはそれらの部品を設置するための枠組みのような役割にとどまるでしょう。
逆に、Block内部の部品を自分の一部としてスタイリングする場合は、先述のスタイリングパターンB・Cどちらかでスタイリングすることになります。Blockのユースケース
コーポレートやブログ、ブランディング、LPなどの情報発信系サイトであれば、よほどの規模ではない限り、この分類でコード化は完成するのではないかと思います。
内部部品はスタイリングパターンB/C(※近年の慣例手法はCのBEM式)のみで作成し、同じ部品が何度か登場したとしても、パターンAの代わりに、SassのExtendやMixin機能で同一コードを流用して完成させるような方法です。参考情報
余談・参考情報になりますが、
body
タグ直下に機能的・慣例的に設置する.wrapper
といった命名の「全体包括要素」もBlockであると捉えると、「Block同士は恒常的にネストする」という意味が理解しやすくなります。※このとき、思考のつじつまが合いやすい命名は.site
です。<body> <div class="site"><!--この中にあるのは「サイト」の表示用データ--> <div class="site-header"> <header>…</header> </div> <div class="site-main"> <main>…</main> </div> <div class="site-footer"> <footer>…</footer> </div> </div> </body>また、コンテンツのBlockも同じ構造を意識してマークアップすることで、サイト全体のコードがフラクタル構造(自己相似)となり、ルールが捉えやすくなります。(※サンプルはBEM記法で記載)
<div class="photo-gallery"><!--この中にあるのは「写真ギャラリー」表示用のデータ--> <section> <div class="photo-gallery__header"> <header>…</header> </div> <div class="photo-gallery__body"> … </div> <div class="photo-gallery__footer"> <footer>…</footer> </div> </section> </div>2 ・ Module
Module(モジュール)は、単体でも機能しそうな中程度の情報の塊です。
カードや、ギャラリーの1区画。会員証を模したようなもの、プロフィールのひと塊、ECサイトの商品一覧、メニューナビゲーションの1区画などが該当するでしょう。多くの場合は
div
によるコンテナに名前が与えられます。Moduleの粒度判断
粒度の判断は、コンテンツ部分とフレーム部分で分けて考えられます。
下位粒度のcomponentが集まったものと捉えるとイメージしやすいかもしれません。
- コンテンツ
- Blockほどの情報の規模感は無いが、単独でも機能しそうな視覚情報の塊
- 場合によっては任意の構造体が入りそうなもの
- その場でリピートして使われそうなもの
- フレーム
- ブランディングエリアや、コンタクト情報 等
- ブランディングエリアや、サイトマップリンク、コンタクト情報 等
Moduleの部品作成方法
自身をグローバルな再利用部品として管理したい時に、
module/
ディレクトリに切り出して管理します。そうではないなら、この粒度のものは、上位粒度の持ち物としてスタイリングが完了しているはずです。Moduleのユースケース/この粒度は必要か
ModuleはBlockと近い存在となります。特にBEM記法を使っているとBEMのBlockの概念と相まって「粒度が違えば全てModuleディレクトリに切り出さないといけないのか?」となる事もあるでしょう。そういった管理が煩雑になる場合は、Blockとして管理しても何も問題ありません。(究極は、制作者が混乱しなければよいのです)
では、定義の意味は?
「であれば結局は無法地帯では?」と思われるかもしれませんが、そうではありません。どんな時にこの粒度が有用かというと、1つは再利用の明示です。
Blockは最上位にあるため、どのように再利用しているのか、もしくはしていないのかはHTMLファイルを要調査。となりますが、Moduleディレクトリに置いただけで「どこかで必ず再利用されている中粒度部品」もしくは「どこで再利用してもよい中粒度部品」として意識づけできます。
最初にBlockのディレクトリにSassファイルを置いていても、後から上記のように明示したくなった場合は移動させることもできます。システム開発との連動
もう1つ有用なパターンは、ECサイトやサービスサイトなどのシステムが絡む時です。
システム側のフロントテンプレートなどにおいて「モジュール」として切り出すものは、この粒度と同じ規模感になるものも多くあります。それぞれ同じModuleという名称のディレクトリで管理すれば、双方が意識上対応したものとして管理できます。このように、実用時には必要に応じて使い分けられる粒度となります。
3 ・ Component
Component(コンポーネント)とは、見出しやボタン、リストや表組などの、単体でもその部品の機能や目的・情報が分かる小さな要素です。
ModuleやBlockから見れば、自分達を構成する小さな部品群で、下位粒度のElementのから見た時には、Elementの組み合わせがComponentであると表現できます。この粒度のものには「構造体」や「文書構造」が入ることはありません。
div
やspan
のラッパーに名前を与えることもあれば、ul
ol
table
などに名前を与えることもあるでしょう。Componentの粒度判断
文書構造や構造体が入る余地・感覚が無いもので、かつ、以下の1~4のうち、1つでも当てはまればComponentとなります。
- 視覚情報
- 1・視覚情報として分割できる
- HTMLコード
- 2・HTMLタグがHTMLタグでラップされている
- 3・内部を自然に拡張できる
- 4・コードとして分割・分離できる
また、レンダリング結果はElementと同一になるが、コード側から見ればComponentと判断できるものがあります。以下のようなパターンです。
コード側から見てComponentになる例
img
タグ単体は後述するElementにあたりますが、これを<div class="image">
などでラップすれば、.image
は立派なComponentです。「分解・分離できる状態」であり、後に内部にキャプションを入れるなど、「自然に拡張できる状態」になっています。同様に、
p
タグだけの文章はElementの粒度にあたりますが、これを<div class="text_box">
といったような命名のボックスでラップすれば、同様にComponentとなります。文章が追加されても、新たなp
タグによって内部を自然と拡張できます。Componentの部品作成方法
自身をグローバルな再利用部品としたい場合に、
component/
ディレクトリに切り出して管理します。そうではないなら、この粒度のものは、上位粒度の持ち物としてスタイリングが完了しているはずです。Componentのユースケース
Componentをグローバルな再利用部品として作成・運用したくなるのは、システム管理画面やシングルアプリケーション系のプロダクト、ブログの記事内の部品、サービスサイトのUI部品などでしょう。
OOCSSの概念と併用する事が多くなるでしょうし、"既製品"としてBootstrapのようなCSSフレームワークを利用する事になるのかもしれません。小規模でシステマチックではない静的サイトであれば、Blockの項に記載したとおり、Componentは全て上位粒度の持ち物としてスタイリングした方が効率よく管理できるでしょう。
部品の集まりをどう捉えるか
この粒度のものは、幾つかの部品が集まり特定の機能になる場合もあります。例えば、ボタンが複数横に並んで連結されていれるような場合です。これはComponentの集まりである。と捉える事もできますし、
div
でラップして「ナビゲーション」という意味の名前を与えればModuleにも、Blockにもできます。
つまり、そのプロジェクトにおいて、対象の部品をどのように管理したいか。という制作者の意思・意図が第一優先です。それをサポートするように、振り分けできる手立てが用意されている。という事になります。参考情報
Componentは特性として2つの属性のものがあります。
1つは、テーブル(table)やリスト(ul,ol,dl)など、HTMLの仕様により内部構造が定められているものです。これらは、HTMLの仕様に従い内部を拡張できますが、使えるタグは限られています。もう1つは、「アイコン+タイトル=メニュー項目」「ラジオボタン+テキスト=選択部品」とするなど、制作者の意図により小さな部品を組み合わせてComponentとしたものです。
※この区分けは粒度分類には影響しません。属性的に2つのものがあるという参考情報です。
4 ・ Element
Element(エレメント)は、表示上の面積に関わらず、視覚情報上もしくはコード上でもそれ以上部品分解できない最小の要素です。
Elementの組み合わせ、もしくは単体を何らかの要素でラップすれば、Componentとなります。
img
やinput
など、直接レンダリングされるタグやspan
、i
などに名前を与える事があるでしょう。Elementの粒度判断
それ以上分割分割できない要素で、一行のテキストや、ラジオボタン、チェックボックスなどです。無理に分割しようとすると、意図した情報伝達ができない、機能不全になる、コードとして成立しないといった不都合が起きるようなものが該当します。
また、粒度はレンダリング時の面積にとは関係がありません。いくら面積の広い画像を配置しようとも、img
タグレベルは一様にElementの粒度となります。どれだけ巨大なアイコンや、ラジオボタンを配置したとしても同じ事が言えます。Elementの部品作成
自身をグローバルな再利用部品としたい場合に、
element/
ディレクトリに切り出して管理します。そうではないなら、この粒度のものは、上位粒度の持ち物としてスタイリングが完了しているはずです。Elementのユースケース
この粒度をグローバルな再利用部品として作成・運用するとなると、独自にCSSフレームワークを作る。もしくは、ドラッグ&ドロップでサイトを作っていくようなサービスを構築する時でしょうか。※他にも用途はあるかもしれません
その他
プレフィックス
実用する際には、これらに名前を与えてからCSSプロパティを書くことになりますが、命名時のプレフィックスのルールはここでは定めません。(ガイドという立場として、特に奨励も制限もしません)
制作の必要性に応じて「再利用前提のものはm-
c-
e-
を付与する」など、それぞれ使い勝手が良いように自由にルールを制定してください。アイデア
これはまだ試せていませんが、1つのアイデアとして、この粒度分類を逆にデザインシステム側に反映できるかもしれません。コーディング側で最適化したものをデザインシステムに乗せられたなら、スムーズに連携できる可能性はあります。
粒度の総括
以上、4つの粒度をコーディングの側面から定義しました。
分類そのものの本質部分を見ればAtomic Designのそれと非常に近いものですが、思考の入り方と語句の定義を変えただけで、人の認識や使用感は異なったものになります。
では、これが万人向けするのか。といえば、それは分かりません。しかし、少なくとも1つの組織と協力会社において使用する限り、破綻などの問題がゼロであることは事実です。HCDCモデル図と今回の「HTML Parts」、そして、次回公開する「Sassファイルディレクトリ管理手法」によって、より多くのサイト種別に対応した設計がおこないやすくなります。
Sassファイル・ディレクトリ管理
これらの粒度の名称は、そのままSassファイル管理ディレクトリの名称として利用することになります。
部品化の方法としては、先述の通り「グローバルに再利用する場合」のみ、その粒度のディレクトリに部品を切り出して管理します。しかし、これらを含めた全体をどのように管理するかは、また別の話となります。これはCSS設計の命題のひとつであり、概念を実務利用するための重要事項となります。
次回紹介するものは、プロジェクトごとにカスタマイズ可能なSassファイル管理の仕組みです。標準ルールを中心として、同じロジックでいくつものサイトタイプに柔軟に対応できます。この記事作成時点での実務利用実績は以下の通りです。
コーポレートサイト / ポータルサイト / サービスサイト / システム管理画面 / ブログサイト / ECサイト(オンラインショップ) / ランディングページ(LP) / イントラサイトこの管理方法についての情報は、投稿次第こちらの記事からもリンクします。
関連記事
クレジット・その他
Ultimate Coding
概要・前提事項
- 設計・考案/構築/記事投稿
- @croco_works - Twitter
- 設計パートナー/技術検証
- @wildwest_kazya - Twitter
この仕組みは、組織所属時に業務効率化のために構築したものであり、許可を得た上で設計者本人が個人活動として公開しています。商用の制作や開発には利用していただけますが、仕組みを販売したり媒体化するなどの、制作以外での商用化はご遠慮下さい。質問その他、何かあれば@croco_worksまでお声かけください。
- 投稿日:2020-02-26T09:59:40+09:00
JavaScriptの連想配列に関する文法
const customer = {"name": "taro", "age": 22}; const {name, age} = customer; console.log(name); console.log(age); // output // "taro" // "age"const name = "taro"; const age = 22; console.log({name,age}): // output // {"name": "taro", "age": 22}
- 投稿日:2020-02-26T05:11:43+09:00
Cognito+Amplifyで二要素認証する(ログイン画面で ID/PW/"二要素用のコード値" を入力して認証する)
概要
- Cognito+Amplifyで二要素認証する。
- ログイン画面に
ID/PW/コード値(二要素目扱い)
の3項目を入力することを前提とする
※なので、二段階認証では無い・・・- codeにはGoogle Authenticator等で生成されるコード値が入る前提とする
実装
Amplify側
下記でサインインする。
※二要素目のパラメータとしてvalidationData
を送信する。Auth.signIn({"username": user_id, "password": user_password, "validationData": { "code": "WinAuth_code" }}) // ※Cognitoの認証前トリガーでcodeがとれる
Amplify.signIn()
のIF参照※
Amplify.signIn()
の第1パラメータをSignInOpts
形式で指定している
- https://aws-amplify.github.io/amplify-js/api/classes/authclass.html#signin
- https://aws-amplify.github.io/amplify-js/api/globals.html#usernamepasswordopts
Cognito側
認証前トリガーを使って、
validationData
のcode
を取得し、コードの検証をする形になる。認証前トリガーのLambda
import boto3 def lambda_handler(event, context): # Usernameに紐づくグループを取得するサンプルコード client = boto3.client('cognito-idp') response = client.admin_list_groups_for_user(UserPoolId=event['userPoolId'], Username=event['userName'] ) print("---- ---- ---- ---- ---- ---- ---- ") print(event) print(response) print("---- ---- ---- ---- ---- ---- ---- ") # コード検証を実行 ※ソースは省略 # エラーの条件によってメッセージを変える # ※ # エラー時にメッセージを変更することしかできない(HTTPのステータスを変えるとかは出来ない)ので、 # コードが誤っている場合は専用のメッセージをAmplify側に返すことになる raise Exception("Cannot authenticate users from this user pool app client") return event認証前トリガーLambdaのログ(Lambdaハンドラ引数の
event
の中身)下記に注目
event['username']
に入力したユーザネームが来ているevent['request']['validationData']
が来ている{'callerContext': {'awsSdkVersion': 'aws-sdk-unknown-unknown', 'clientId': 'xxxxxxxxxxxxxxxxxxxxxxxxxx'}, 'region': 'ap-northeast-1', 'request': {'userAttributes': {'cognito:token_nbf': '1582593027733', 'cognito:user_status': 'CONFIRMED', 'sub': '67eb1ed1-240b-4861-9844-f82ebc08d2f8'}, 'userNotFound': False, 'validationData': {'aaaa': '12345'}}, 'response': {}, 'triggerSource': 'PreAuthentication_Authentication', 'userName': 'hogehoge', 'userPoolId': 'ap-northeast-1_xxxxxxxxx', 'version': '1'}
- 投稿日:2020-02-26T01:54:25+09:00
JavaScriptの便利関数
あったら便利な汎用的javascript関数をまとめました。
deepメソッド
ネストしたオブジェクトにアクセスするときに使用すると、存在チェックが出来る
const deep = (obj, path) => { path = path.split(/\.|\[|\]/).filter(v => v) for (const k in path) { if (!obj) return false else if (obj[path[k]]) obj = obj[path[k]] else return false } return true }使い方
testオブジェクトに、test2プロパティが存在している
その中にtest3プロパティが存在していて、かつ中の値も存在しているか確認const test = { test2: { test3: true } } console.log(deep(test, 'test2.test3'))出力結果
true
存在している場合は
true
、存在していない場合はfalse
が返ってくるdelayメソッド
async/await
を使用するときに、setTimeout
でPromise
を返すconst delay = ms => { return new Promise(resolve => setTimeout(resolve, ms)) }使い方
await
でdelay
メソッドを使い、引数にはミリ秒単位で時間を入れる、その間その後の処理は行われない(async function() { await delay(3000) console.log('3秒経ちました。') }())出力結果
3秒経ちました。3秒後に「3秒経ちました。」と出力
参考文献
この記事は以下の情報を参考にして執筆しました。
- 投稿日:2020-02-26T01:07:11+09:00
emotion (emotion.js) のStyled Componentsで作成した要素にカスタム属性を渡したくなったら (shouldForwardProp)
今日ハマったのでメモ。
Reactはバージョン16から要素に好きに属性を生やせます
Reactはバージョン16からカスタム属性の利用を認めています。
たとえば、下記のような属性指定ですね。
<a mycustomattr="customvalue">foobar</a>上記の場合だときちんと
mycustomattr="customvalue"
が実際のDOMにレンダリングされます。もともとReactでは、HTML公認のカスタム属性である
data-**
や、幅広い語彙を持つaria-**
は利用を認められていたのですが、その他の自作の属性、あるいはHTML5でいなくなった古い属性(e.g.<td>
要素のalign
属性)は、カスタム属性が使えないと表現できません。emotionのStyled Componentsはそのままだとカスタム属性をはたき落とします
そして本題ですが、タイトルの通りemotionのStyled Componentsは、デフォルトでカスタム属性をはたき落とします。
たとえば、
const CustomElem = styled.div` color: red; ` // @ts-ignore return <CustomElem mycustomattr="customvalue">Hello</CustomElem>(
@ts-ignore
はTypeScriptさんがmycustomattr
なんてないよ!とエラーを出すのを抑制するために入れています。JSの人は要りません。)上記のコードだと
mycustomattr
がはたき落とされます。基本的には、is-prop-validという実装に従って、HTMLに無さそうな属性は自動的に消してくれるようです。今までのReactであれば、存在しない属性を渡すと警告を出していたので、特に自前propsが無意識に渡されて警告が出がちなStyled Componentsにおいては重要な機能と言えるでしょう。
emotionでカスタム属性を通す方法
ただ、当然このままだと困るケースもあるわけで、じゃあそういう場合はどうするかというと、ドキュメントに書いてあるとおり(←最初からちゃんとドキュメントを読めよ!)、
shouldForwardProp
を指定して、自分のカスタム属性を通してあげましょう。const CustomElem = styled("div", { // mycustomattr と children(子要素) のみ許可する shouldForwardProp: (props) => ["mycustomattr", "children"].includes(props) })` color: red; ` // @ts-ignore return <CustomElem mycustomattr="customvalue">Hello</CustomElem>ちゃんと結果のDOMに
mycustomattr
がいるはずです。逆に、他の属性を渡しても何もDOMに影響しないはずです。
- 投稿日:2020-02-26T00:29:09+09:00
【OnsenUI】画面遷移とアニメーションの設定方法
こんにちは。
OnsenUIの学習中につまずいた、画面遷移の方法をまとめてみます。画面遷移
main.jsif (page.id === 'page1') { page.querySelector('#switch_button').onclick = function() { document.querySelector('#myNavigator').pushPage('page2.html',slide); }; } else if (page.id === 'page2') { page.querySelector('#return_button').onclick = function() { document.querySelector('#myNavigator').popPage(slide); }; };画面遷移には、
pushPage
popPage
メソッドを使用します。
引数にはあらかじめ作成したページと、アニメーションを指定します。(poppage
にはアニメーションのみ)アニメーションの設定
main.jslet slide = { animation: 'slide',onTransitionEnd: function(){} };
animation
には任意の値を指定できます。
OnsenUIで用意されているアニメーションは以下の4つ。
- slide
- lift
- fade
- none
参考文献