Building customized bootstrap theme

なんかタイトルの英語が間違ってたらごめんなさい。
備忘録です。

今職場でAccess + SQLServer2005 で作られている業務用のデスクストップアプリケーションをウェブシステム化する仕事を、本来の業務と並行で行っているのですが、僕が一番苦手なUIデザイン、モバイル携帯向けの含めて、どうしようか・・・と考えたとき、やっぱりネットでの情報が比較的多いbootstrapで・・・となりますよね💦

そこで問題になるのはやっぱりブートストラップ臭が・・・ということでしょうか。。。僕は古いタイプの人間なんで愚直に一個一個CSS、セレクタ、プロパティをガシガシ上書きしてました。これが実に苦痛で。。。

そこで、bootstrap4に移行するついでにSASSでカスタマイズするフローを学ぼう、というわけです(^▽^)/

bootstrap4のテーマの変更(Themingって日本語でなんていうんだ?)の仕方って、ググればググるほど、一体何が正解なんだ?という気になります。僕はGulpとか、gruntとか、webpack とか・・・ググらないと分からない・・・というレベルのオッサンでなんで、今時のトレンデーな、マックブック片手にバリバリ仕事をこなしている、最先端イってるイケてる人たちから見ると、アホかいな?というレベルの備忘録ですので、あらかじめご了承のほど。

余談です。フロントエンド開発が何を意味しているのか僕は正直わかんないです。最近は特についてけないです。Gulpとかgruntとかwebpackとか無縁の職場で、ナニソレ、おいしいの? いや普通に bootstrapの色を変えたり、角丸なくしたり、したいだけなんですぅ。未だに git じゃなくて svn だしぃ。

さて、まずはともかく、本家本元の手順に従いましょう。
ビルドツールのインストールです。https://getbootstrap.com/docs/4.3/getting-started/build-tools/
僕は Windowsユーザーなので、WSL(ubuntu16.04)を使用します。

(1) Node.js のインストール・・・これは適当に入れる。僕は以下の手順でいれます。
一旦aptでインストールし、nパッケージを入れ最新のものに入れ替えた後、apt removeします。

$ sudo apt install -y nodejs npm
$ sudo npm cache clean
$ sudo npm install n -g
$ sudo n stable
$ sudo ln -sf /usr/local/bin/node /usr/bin/node

$ sudo apt purge -v nodejs npm

(2) 上記サイトでは ruby のインストールも書かれていますが、テーマの変更だけしたい場合には必要ないと思います。まぁ、今時の開発者なら ruby は初めからインストールしているでしょうし・・・割愛(^^;

(3) 本家からbootstrapのソースをダウンロードし、適当なディレクトリに展開し、そのディレクトリで npm install で依存しているパッケージをインストールし、npm run css とすると、dist ディレクトリに css がコンパイル、ミニファイされたcssができあがります。

さて・・・ここからが本題です。

本家サイトのTheming(https://getbootstrap.com/docs/4.3/getting-started/theming/)を見るとカスタマイズ方法が書かれていますが・・・おそらくNode.jsに詳しくない、あるいは初めて触る人にとっては、そのページは何の参考にもなりません。。。custom.scssを作って・・・とか書いてますが・・・それで?って感じです。
scssファイルからcssをコンパイルおよびミニファイする具体的な手順とかほとんど書かれていません。

このあたりをググってみても、上記のgulpだの、gruntだの webpackだの、の手順とかがヒットして、オッサンが一番知りたい事の情報がでてきません。単に探し方が悪いのかも。。。
そこで自分なりに調べた結果、以下の手順でカスタマイズするフローに辿り着きました。

以下のフローでは、オリジナルのbootstrapには一切手を付けません。バージョンが上がるといろいろ困りますからね。
具体的なテーマをカスタマイズする方法は、本家サイトの Theming ページを参考にしてもらい、ここでは自分が用意したカスタマイズ用の.scssファイルを、どのように配置して、どのようにビルドするのかを書き留めておきます。

(0) 前準備として・・・

git がインストールされていなければインストールしときます。bootstrapのソースは git clone で取るようにしますんで。

(1) 作業用に適当なディレクトリを作り・・・

以下のようにディレクトリ・ファイルを配置します。。。各ファイル(a,b,c1~3)については後述します。

$ tree -n
.
├── babel.config.js  (a)
├── bootstrap (bootstrapのソースを置くディレクトリ)
├── dist (コンパイルされた css/js の置き場)
│   ├── css
│   └── js
├── package.json (b)
└── scss
    ├── custom-bootstrap-grid.scss (c1)
    ├── custom-bootstrap-reboot.scss (c2)
    └── custom-bootstrap.scss (c3)

(a) babel.config.js

bootstrapのソースにある、.babelrc.js をコピーしてこの名前にリネームします。JSファイルをコンパイルする際に単純にコピーして配置しただけだとエラーになってしまいました。理屈は知りません。すみません。npm-babelのサイトを斜め読みしたら、このファイル名に行きつきました💦

(b) package.json

これもbootstrapのソースにある、package.json をそのままコピーし、カスタマイズ用に修正しました。僕にとっては要らない機能もあるので逐一調べて不要なものを削除しまくり、以下のコードに行きつきました。内容については・・・よく分かりません。調べてください。すみません。

package.jsonは、npm(node package manager)が管理するファイルで、scriptsっていうキーにコマンド名、値に実行するコマンドラインを記述していくみたいです。
npm run コマンド名 で、そのコマンド名の値のコマンドラインが実行される、みたいな。makeみたいなもんか?

長くなりましたが、コピーした package.jsonファイル内のパス指定されている部分を修正したり、単体テストとかlintとか、サーバー機能、ドキュメントの構築などのビルドツールは基本必要ないので、片っ端から削除しました。テーマのカスタマイズ用にcss/jsのビルドさえできればいいという事にフォーカスしています。

通常はファイルを修正したら即反映されるような監視タスクを入れるのが開発のセオリーみたいなのですが・・・あれもこれもとやってると、結局、開発環境構築オタクになってしまうんで、やめときます。開発環境を作りたいんじゃなくて・・・コードを書くのが目的!

{
  "name": "custom-bootstrap",
  "description": "custom bootstrap4",
  "scripts": {
    "clone-bootstrap": "git clone https://github.com/twbs/bootstrap.git -b v4.3.1 --depth 1 bootstrap",
    "css": "npm-run-all css-compile css-prefix css-minify",
    "css-main": "npm-run-all css-compile-main css-prefix-main css-minify-main css-copy",
    "css-compile": "npm-run-all --parallel css-compile-*",
    "css-compile-main": "node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/custom-bootstrap.scss dist/css/bootstrap.css && node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/custom-bootstrap-grid.scss dist/css/bootstrap-grid.css && node-sass --output-style expanded --source-map true --source-map-contents true --precision 6 scss/custom-bootstrap-reboot.scss dist/css/bootstrap-reboot.css",
    "css-minify": "npm-run-all --parallel css-minify-*",
    "css-minify-main": "cleancss --level 1 --format breaksWith=lf --source-map --source-map-inline-sources --output dist/css/bootstrap.min.css dist/css/bootstrap.css && cleancss --level 1 --format breaksWith=lf --source-map --source-map-inline-sources --output dist/css/bootstrap-grid.min.css dist/css/bootstrap-grid.css && cleancss --level 1 --format breaksWith=lf --source-map --source-map-inline-sources --output dist/css/bootstrap-reboot.min.css dist/css/bootstrap-reboot.css",
    "css-prefix": "npm-run-all --parallel css-prefix-*",
    "css-prefix-main": "postcss --config bootstrap/build/postcss.config.js --replace \"dist/css/*.css\" \"!dist/css/*.min.css\"",
    "js": "npm-run-all js-compile js-minify js-move",
    "js-main": "npm-run-all js-lint js-compile js-minify-main",
    "js-compile": "npm-run-all --parallel js-compile-*",
    "js-compile-standalone": "rollup --environment BUNDLE:false --config bootstrap/build/rollup.config.js --sourcemap",
    "js-compile-bundle": "rollup --environment BUNDLE:true --config bootstrap/build/rollup.config.js --sourcemap",
    "js-compile-plugins": "node bootstrap/build/build-plugins.js",
    "js-minify": "npm-run-all --parallel js-minify-main",
    "js-minify-main": "npm-run-all js-minify-standalone js-minify-bundle",
    "js-minify-standalone": "uglifyjs --compress typeofs=false --mangle --comments \"/^!/\" --source-map \"content=bootstrap/dist/js/bootstrap.js.map,includeSources,url=bootstrap.min.js.map\" --output bootstrap/dist/js/bootstrap.min.js bootstrap/dist/js/bootstrap.js",
    "js-minify-bundle": "uglifyjs --compress typeofs=false --mangle --comments \"/^!/\" --source-map \"content=bootstrap/dist/js/bootstrap.bundle.js.map,includeSources,url=bootstrap.bundle.min.js.map\" --output bootstrap/dist/js/bootstrap.bundle.min.js bootstrap/dist/js/bootstrap.bundle.js",
    "js-move": "cross-env-shell shx mkdir -p dist/js && cross-env-shell shx cp -r bootstrap/dist/js dist/",
    "dist": "npm-run-all --parallel css js",
    "dist-clean": "cross-env-shell shx rm -f dist/{js,css}/*"
  },
  "devDependencies": {
    "@babel/cli": "^7.2.3",
    "@babel/core": "^7.2.2",
    "@babel/plugin-proposal-object-rest-spread": "^7.3.2",
    "@babel/preset-env": "^7.3.1",
    "autoprefixer": "^9.4.7",
    "babel-eslint": "^10.0.1",
    "babel-plugin-istanbul": "^5.1.0",
    "bundlesize": "0.15.3",
    "clean-css-cli": "^4.2.1",
    "cross-env": "^5.2.0",
    "find-unused-sass-variables": "^0.3.2",
    "glob": "^7.1.3",
    "node-sass": "^4.11.0",
    "npm-run-all": "^4.1.5",
    "postcss-cli": "^6.1.1",
    "rollup": "^1.1.2",
    "rollup-plugin-babel": "^4.3.2",
    "rollup-plugin-commonjs": "^9.2.0",
    "rollup-plugin-node-resolve": "^4.0.0",
    "shelljs": "^0.8.3",
    "shx": "^0.3.2",
    "uglify-js": "^3.4.9"
  },
  "engines": {
    "node": ">=6"
  }
}

上記 scripts を見てもらえれば、だいたい何をやってるのか分かると思います。
devDependencyは・・・必要なnodeプログラムの一覧?で、npm install すると、これらのプログラムが node_modules ディレクトリにインスコされるみたいですぅ。知らんけど。知らんけど。

(c1 ~ c3)bootstrapの下記ファイルをそれぞれインポートしてカスタマイズするファイルです。

  • bootstrap/scss/bootstrap.scss
  • bootstrap/scss/bootstrap-grid.scss
  • bootstrap/scss/bootstrap-reboot.scss

これは Theming でも説明されています。各ファイルの内容は・・・

/*******************************************************************************
 ファイル名: ./scss/custum-bootstrap.scss
ここに bootstrap本体の変数SASS を記述(上書き)していく。
その方法は、Theming を参照のこと。
*******************************************************************************/
$primary:  orange; 
.
.
.

/* ソース本体をインポート */
@import "../bootstrap/scss/bootstrap";

./scss/custom-bootstrap-grid.scss、./scss/custom-bootstrap-reboot.scss も同様です。

これらの./scss/custum-bootstrap*.scssを自分用にカスタマイズを施したあと、最後はビルドします。
カスタマイズは、主にbootstrap/scss/_variables.scss の中で定義されている変数を変更したりするのがカスタマイズの中心になってくると思います。もちろん、独自のスタイルを定義したければ、ここに書きます。

(2) コンパイル処理

./scss/custom-bootstrap*.scss の編集が終わったら、ビルドします。
順番としては、bootstrapソースを取得してから、npm run dist します。
distは、js,cssを一緒にやる感じです。

# まず、bootstrapのソースをbootstrapディレクトリに取得し、格納します。
# package.json を見ればわかりますが、git clone しているだけです。
$ npm run clone-bootstrap

# もし css/js すべてをビルドしたい場合は、dist
$ npm run dist

# css だけ欲しかったら css
$ npm run css

bootstrapをcloneするとき、v4.3.1のブランチを取得していますが、最新のものが必要であれば、”-b v4.3.1″の部分を消す。また”–depth 1″を消すと過去の履歴全部取得するので異常に時間がかかりますので消さない方がいいと思います。

なお、自分でソースをダウンロードする場合は、clone-bootstrapは実行する必要ありません。

lintとかテストとか一切省いているのでエラーが出たら・・・自力で何とかする!

WSL(Ubuntu)-PHPからSQLServerへの道のり

2019年5月20日 若干修正


「CentOSからWindows上のSQLServerへの道のり」のつづきです。

LinuxからWindows上の SQLServerへのアクセス方法については、世間的にはあまり需要がないのでしょう。まぁ、Linuxとかのunix系のOSでは、SQLServerなんて採用しないし、逆も然り。。。困ったもんだ。。。

さて、Linuxの各ディストリビューション用のMicrosoft製のODBCドライバが提供されていて手順を踏むと、LinuxからSQLServerへODBC経由でアクセスすることができました。

今度は LAMP環境、PHPから文字化けさせずにCRUDすることができるか、ウェブアプリケーションをちゃんと実装できるか、確認です。とりあえずLinux各ディストリビューション用にマイクロソフト製のODBCドライバをインストールしていることが前提です。

PHPでたとえば、以下のようなコードでテーブルを作成し、SQLServer Management Studioとかで確認すると、日本語が全部文字化けします。
sqlcmdコマンドで日本語交じりのSQL文を発行すると化けないので、おそらく、PHPの問題でしょう。DSNで odbc: を使うのがだめなんでしょうね。odbcドライバをインストールしたんだから、当然odbcプレフィックスを使うものだと勘違いしてまして、これが罠でした・・・。日本語関係の処理が全くされない。。。この辺、よくわからん・・・。知識が圧倒的に足りない。SQLServerのODBCドライバとsqlsvr(PHP SQLServer用のドライバ?)の関係が全然わからない。PHPのマニュアル見てもよくわからない・・・。

// これが間違い
$pdo = new PDO('odbc:Driver={ODBC Driver 13 for SQL Server};Server=localhost;Database=Sample','dbuser','dbpass');
$pdo->exec('CREATE TABLE tbl_hoge(hoge_id int NOT NULL,hoge_txt nvarchar(100))');
$pdo->exec("INSERT INTO tbl_hoge values(1,N'日本語で挿入・・・なんかエロいな')");

接続文字列でエンコーディング関係のパラメータがあるのかなと、調べてみたけどないっぽい。さらにネットでの情報がほとんどなく。。。ヒットするのはFreeTDSを使ったものばかりで、多くはPHP5の情報ばかりで、PHP7以降のものは出てこず。。。

で、困ったときはグーグルで検索・・・ではなく、まずマイクロソフトの公式のドキュメントを漁りましょうってことですね(^^;
ググらなくても最近のマイクロソフトはちゃんとドキュメントを用意してくれてます。(MSも変わったな。。。)

Build an app using SQL Server


上記サイトの PHP ⇒ UBUNTU をクリックすると、Linux版 SQL Serverのセットアップから詳細な手順が書かれています。英語ですが、簡単な英文なので読みましょう!英語は喋れなくても、聴き取れなくても一向に問題はないけど、英語の読解能力は必須!ちゃんと読めるようにしましょう!!!
日本人がいくら優れたシステムを作れたとしても、英語で説明できなければ、世界には通用しませんし、この先世界中の開発者がこぞって日本語を理解してくれるとは到底思えないからです。

今までSQLServer用のODBCドライバとPHPでのSQLServer用のドライバ、それぞれが別々に説明がされてて、一体何がどうなってってるのか理解できなかったけど、上記サイトで Ubuntu + PHP では、この手順、Redhat系では、この手順、という風にまとめて手順が説明されているので、これで悩まなくて済むようになった。PHP7以降限定ですけどね。 まぁPHP5系はこの先消えていく(deprecated)のでまぁいいか、という感じ。

要するに ODBCドライバに加えて、peclでsqlsvr/pdo_sqlsvrをインストールすれば完了。やっと 非Windows環境でも労せずSQLServerへフツーにアクセスできるようになりました。

上記マイクロソフトのサイトには、Linux用のSQL Serverのセットアップから説明されていますが・・・SQLServerは Windows用のものをインストールしましょう。というか、開発マシンがWindowsの場合は、素直にWindows用のSQLServer Developper Editionをインストールした方がいいです。開発目的ならライセンスフリーですし。(サーバー環境で運用はできないけど)
開発マシンがMacやLinuxの方は・・・そもそもSQLServerに接続するような仕事してないでしょ?w

WSL(Ubuntu)でPHPをインストールしていない場合、aptで適当にphp7系をインストールしてください。その際、php-dev パッケージは必須です。
また、最新のsqlsrv,pdo-sqlsrvドライバはphp7.0をサポートしないので、最新に拘る人はphp7.1以上にするべし?php7.0をサポートするMicrosoftのsqlsrv/pdoドライバのバージョンは5.3です。最新は確か5.6だったかな?
システム要件:https://docs.microsoft.com/ja-jp/sql/connect/php/system-requirements-for-the-php-sql-driver

$ sudo apt install php php-cli php-dev php-... (必要なパッケージ)
# apacheで動作するには必要
$ sudo apt install libapache2-mod-php

1, 先に マイクロソフトのサイトからODBC Driver for SQLServer をインストールしておく(上述)

2, sqlsrv/pdo_sqlsrv のインストール (ubuntu 1804 の場合)

$ sudo apt install php-dev
$ sudo pecl install sqlsrv
$ sudo pecl install pdo_sqlsrv
$ sudo su 
# echo "extension=pdo_sqlsrv.so" > /etc/php/7.2/mods-available/pdo_sqlsrv.ini
# echo "extension=sqlsrv.so" > /etc/php/7.2/mods-available/sqlsrv.ini
# exit
$ sudo phpenmod -v 7.2 -s ALL  pdo_sqlsrv sqlsrv

apache2な人は再起動するべし。
参考リンク:the installation instructions on Microsoft Docs.

3, PHPで確認
PDOで、DSNのプレフィックスをodbc: ではなく sqlsrv: で。

$pdo = new PDO('sqlsrv:Server=localhost;Database=Sample','dbuser','dbpass');
$pdo->exec('CREATE TABLE tbl_サンプル(hoge_id int NOT NULL,hoge_txt nvarchar(100))');
$pdo->exec(sprintf('INSERT INTO tbl_hoge values(1,N%s)',$pdo->quote('日本語で挿入・・・なんかエロいな'));

参考リンク: https://github.com/Microsoft/msphpsql/tree/master/sample

文字列リテラルをNプレフィックスをつけずにINSERTとすると絵文字が化ける。文字列リテラルの場合は Nプレフィックスを忘れずに。。。
ただ、プリペアドステートメントを利用する場合、自動的にNプレフィックスはつけてくれるみたい。SQLServer Data Profilerで実際実行されたSQL文を確認すると、PDO::execでは自動的にNプレフィックスはつけてくれないみたい。まぁ当たり前といえば、そうなんだけど。。。

あと、東京オリンピックまでには、apt install php-sqsrv / yum install php-sqlsrv とか標準のリポジトリでインストールできるようにしてほしい。。。

\(^o^)/

Inconsolata + BIZ UDゴシック

新しい iPad Pro 発表されましたな。
1TBのやつが欲しいけど、さすがに18万は高いなー、

閑話休題

Windows10 1809(October 2018 Update) から BIZ UDフォントが標準搭載されたので、gVimで試す。
ASCII文字(guifont)を Inconsolata、日本語(guifontwide)をBIZ UDゴシックに設定しましたが、なかなかイイ感じです。


(全景)

エディタによって BIZ UDフォントを指定すると、半角英数の文字幅が強制的に2倍になってしまって悲しい感じになるんですが・・・これどーすればいいの???(^^;;;

start的なコマンド


台風の影響で、帰宅命令が発動され、早退してきて急に暇になった。
まぁ、そんなことは兎も角。

ほとんどのcmdやpowershellのようなコマンドプロンプト操作は WSLのUbuntuで済ませられるようになりました!が、内部コマンドの start だけは、コマンドプロンプトに頼るしかない。

cygwinならcygstart的な、wslstart みたいなコマンドが欲しいところ。ググれば github にそのものズバリの wslstart のシェルスクリプトがあったが、スクリプト的なものは使いたくないし・・・だって、他所のパソコン触るとき無いとガッカリするよね。他所様のパソコンに勝手にスクリプトファイル置いたら怒られるよね・・・。

つーか、”start . ” でカレントディレクトリのフォルダウィンドウが開ければそれでいいんですよ。。。。

ってなわけで、alias を一個追加。これなら、覚えられるし、他所のパソコン触るときもチャチャっと書ける。

alias start='cmd.exe /c start'

おいらのパソコンの ~/.bash_alias に追記した。。。

gVim の :terminal から “start .” とかやる。助かる~(^^;;;


#追記 2018/09/17
やっぱり パス変換の判別が欲しい・・・っていう欲求が出てきて、数行のシェルスクリプトをかます事にした。
WSLでのstartコマンド簡易ヘルパー

gvim(+kaoriya) + WSL Part2

:prev
この前のつづきです。

シェルをWSL(ubuntu bash)にすることで、:terminalの他、外部コマンド実行(“!” から始まるやつ)をWSL内で完結することができました。
が、ただ一点、:terminal {command} にする場合、:terminal bash -c '{command}' としないとエラーになってしまうので、これが不満。

そこで、Wslterm というユーザー定義のコマンドを _gvimrc に追加することで、ラクしよう、と、こういうわけです(^^;
ヘルプを斜め読みしてとりあえず関数とコマンドの定義の仕方を最低限覚えて、以下の記述に辿り着く。
ほんとはもっとスマートなやり方があるんだと思いますが・・・素人の思いつきです。。。

" terminal の WSLラッパー コマンド (かなり修正:2018/7/13 0:02)
" ・・・なんかトンチカンなことをやってる気がしてきた・・・
" append to ~/_gvimrc 
set shellslash
set shell=C:/WINDOWS/system32/bash.exe
set shellcmdflag=-c
set shellquote=\"
set shellxescape=
set shellxquote=

function! Wslterms(c,f,l,...)
  let cmdline = []
  let option = []
  let i = 0
  while i < a:0
    if stridx(a:000[i],'++') == 0
      call add(l:option,a:000[i])
    else
      call add(l:cmdline,a:000[i])
    endif
    let i += 1
  endwhile
  let l:options = len(l:option) ? join(l:option," ")." " : ""
  let l:cmd = "terminal " . l:options

  if len(l:cmdline) > 0
    let l:cmd = printf("%s%s %s %s",l:cmd,&shell,&shellcmdflag,shellescape(join(l:cmdline," ")))
  endif

  if a:c 
    let l:cmd = join([a:f,a:l],",") . l:cmd
  endif

  execute(l:cmd)
endfunction
command! -nargs=+ -complete=file -range=0 Wslterm call Wslterms(<count>,<line1>,<line2>,<f-args>) 

これで、:Wslterm perl %とか、’<,'>Wslterm hogehoge とかやると、bash -c をつけて簡易的に :terminalの真似ができました(^^;; おまけで、gvimのterminalの中で、WSL(ubuntu)内のvimでファイルを編集(左)とかできちゃう!w

ただ、vim自体操作は慣れてきたとはいえ、まだよく分かっていないのでこういうアプローチでいいのか、よく分かんないです。またvimスクリプトの本でも買って勉強しよ。

■補足 2018/09/24
guioptions に “!” を追加すると :shell コマンド時、コンソールウィンドウが立ち上がるのではく、gVimのウィンドウを使用するみたい。知らんかった・・・・。

:set guioptions+=!

_gvimrcに書いとくと、かなりイケてる感が味わえるかも(^^;
ちなみに僕の guioptions は・・・

"snip
guioptions=egmrL!
"snip

となっております。。。

:continue
つづきは part3で