VScode住人の探検記

Visual Studio Codeでなんでもこなすのがポリシー。LaTeX(2020/7/19~), C(2021/1/25~), C#(2/4~), HTML&CSS(2/14~), Python(2/16~), JavaScript(2/28~), jQuery(3/18~), Sass(Scss)(3/20~),シェルスクリプト(3/21~), jCanvas(5/21~), WordPress(5/23~), PHP(5/31~)

サイト開設のお知らせ

お久しぶりです。

はてなブログのカスタマイズという形でHTMLやCSSを学習していましたが、自分で一からCMSを構築するスキルが身についたので、Laravel・Vue.js・サーバ構築などの勉強も兼ねて自分専用のブログサイトを立ち上げました。

tetracalibers.net

当ブログは2020年7月20日に開設し、初記事はLaTeXの環境構築の雑なメモ書きでしたね… あの頃はパスの意味すらわかりませんでしたが、初めて黒い画面に触れたその日がすべての始まり。

LaTeXのマクロ作りを足掛かりにプログラミングを始めて10ヶ月。良縁もあり、いろいろな経験をさせていただき、ありがたいことに来春からプログラマとしての就職も決まりました。

ちなみに新ブログサイトはこんな感じです。LaTeXで作ったPDF教材などもすべて公開しています。

tetracalibers.net

今後は自サイトでブログを投稿していきますが、思い出が詰まっているので当ブログの記事はそのまま残しておきます。

稚拙な記事ばかりで今となっては恥ずかしくもありますが、ご愛読ありがとうございます。 新ブログサイトにも遊びに来ていただけたら嬉しいです。

tomixy

【改良版】VScodeでのDart Sass環境構築、さらに自動で作業フォルダ作成

jQueryを勉強中なのだが、動作を確認するにはhtmlファイルを作成し、jsファイルを作成し、cssファイルを作成し、場合によっては画像も作業フォルダに入れておかなければならない。
これらをすべて同じフォルダに入れておくとごちゃごちゃになるので、作業フォルダ内にいくつかフォルダを作成し、jsファイルはjsフォルダに、cssファイルはcssフォルダに、画像はimagesフォルダに入れておくことにしよう。
また、私はsassを用いてcssを書いているので、scssファイルを入れておくsassフォルダも作っておこう。そしてコンパイルによって生成されたcssファイルはcssフォルダ内に格納されるようにしたい。

…さて、こんなことをいちいち手動で行うのは泥臭すぎるので、ここはプログラミングの力を借りて自動化しよう、というのが本記事の主題である。
快適なWebページ制作環境となる雛形フォルダを一発で作成できるようにしたい。さらに、前記事のコードを改良し、scssファイルのコンパイルも簡単に行えるようにしたい。

本記事で実現するもの

快適なWebページ制作環境となる雛形フォルダの作成

プロジェクトフォルダを置きたいフォルダをVScodeで開いた上で、shift ctrl Bmacならshift(⬆️) command B)を押すと、画面上部が次のようになる。

f:id:nix_campane:20210426094742p:plain
shift ctrl B(macならshift(⬆️) command B)を押した後

そこで、Sass new project createを選択する。

f:id:nix_campane:20210426095153p:plain
Sass new project createをクリックした後

デフォルトではプロジェクトフォルダ名がsampleになっているが、ここはお好みの名称に書き換えてEnterキーを押せば良い。

f:id:nix_campane:20210426095605p:plain
フォルダが作成された状態(例として、sampleフォルダを作成した)

sampleフォルダの中身を覗いてみよう。

f:id:nix_campane:20210426095849p:plain
sampleフォルダの中身を表示した状態

自動的にimagesフォルダ、cssフォルダ、sassフォルダ、jsフォルダ、index.htmlが作成されているのがわかる。config.rbについては後述する。
それぞれのフォルダの中身も覗いてみよう。

f:id:nix_campane:20210426110110p:plain
各フォルダの中身まで表示した状態

scripts.js、style.scss、index.htmlは空のファイルであるので、この中にコードを書いていけば良い。もちろん、お好みでファイル名を変えることもできるが、大概はこのタイトルのままでいいだろう。
また、cssフォルダ内にはreset.cssが用意されている。これは基本的に編集せず、そのままhtmlファイル内で読み込めば良い。

こうして、ショートカットキーとプロジェクト名の入力だけで、快適にWebページ制作を始められる環境が整う。

.scssファイルのコンパイル

コンパイルしたいscssファイルをVScodeで開いた状態で、 1. shift ctrl Bmacならshift(⬆️) command B)を押す 2. Sass compileを選択する

すると、そのscssファイルがcssファイルに変換され、cssフォルダ内に吐き出される。

実現のための設定

さて、上述の便利機能をVScodeに増設するまでの過程をこれから解説していく。

インストールするもの

Visual Studio Code
コードを編集するためのテキストエディタテキストエディタとは名ばかりで、実際のところこれ一つでなんでもできる統合開発環境
普通、統合開発環境といえば各言語専用だが、VScodeは本当になんでもできる。今のところ、C, C++, C#, Python, JavaScript, Ruby, HTML, CSS, Sass(Scss), LaTeX…などあらゆる言語をここで編集し、実行できている。
適当にググってカスタマイズしてほしい。
node.js
node.jsをインストールすると使えるようになるnpmコマンドがこの記事では(というかいろいろな場面で)必須になる。
インストール方法はOSによって異なるようなので、ググって…
RubyCompassと共存させる場合)
Sassコードをコンパイル(ブラウザが認識可能なCSSに変換)するために必要。
Macは最初から入っているのでスルー。Windowsの方は申し訳ないがググって…
Sass(SCSS)
CSSプログラミング言語のように効率的に書ける言語。
黒い画面からgem install sassでインストールできるはず。Macの方はsudoを先頭につけて。
compass
Sassで使える便利グッズ集(Sassのミックスインや関数をライブラリ化したもの)。Sassのコンパイラとしても使える。
黒い画面からgem install compassでインストールできるはず。Macの方はsudoを先頭につけて。 Compassのサポートは2016年に終了しているので、今から使い始めるのは推奨されていない。
この記事では、基本的に雛形作成(ディレクトリの整理整頓)とreset.cssの生成のためだけにCompassを利用し、Sassのコンパイルには、速度が遅いCompassコマンドは使用せず、これからも新機能が増築されていく最新のDart Sassを用いる。

しかし、どんどん新たなツールが生み出されているとはいえ、CSSスプライト作成機能など、未だCompassにしかない機能もいくつかあるらしい。そんなわけで、いつでもCompassも使えるように環境だけは残しておくことにする。

npmコマンドでインストールするもの

まず、sassのコンパイルに必要なものをインストールする。
前記事ではローカルインストールしていたが、プロジェクトフォルダ作成の度にいちいちダウンロードするのは時間がかかるので、個人で使う分にはグローバルインストールで良いと思う。というわけで-gオプションをつけている。

Terminal or CommandPrompt

npm install -g sass fibers

次に、ベンダープレフィックス(ブラウザごとの表示の差異をなくすために必要なコード)の自動付与に必要なものをインストールする。

Terminal or CommandPrompt

npm install -g postcss postcss-cli autoprefixer

PostCSS
CSSを変換するツール
postcss-cli
PostCSSを黒い画面で使えるようにするツール
Autoprefixer
PostCSSによってベンダープレフィックスを追加するツール

初期設定

MySassCreate.shの配置

次のMySassCreate.shをどこかしらに置く。

zshでしか動作確認していないが、bashでも使えるはず。(というかそもそもbashのためのコード)
windowsの方は…そうだなあ。私はwindows時代、この記事を見ながらbashを導入した気がする。

参考までに、私はホームディレクト/Users/tomixyMyShellScriptというフォルダを作って、その中にMySassCreate.shを置いている。
置き場所に応じて、以降登場する/Users/tomixy/MyShellScript/をそのディレクトリ名に書き換えてね。

macの方はchmod u+x /Users/tomixy/MyShellScript/MySassCreate.shを実行するのを忘れずに。これを実行しないとMySassCreate.shは動きません。

MySassCreate.sh

#!/bin/sh

PROJECT=$1

compass create $PROJECT

cd $PROJECT 

mkdir css
cd stylesheets
rm -f ie.css
rm -f print.css
mv screen.css ../css

cd ..
rm -d stylesheets

cd css
mv screen.css reset.css

cd ../sass
rm -f *.scss
touch styles.scss
cd ..

mkdir js
cd js
touch scripts.js
cd ..

mkdir images
touch index.html

task.jsonを開く

  1. shift ctrl Pmacならshift(⬆️) command P
  2. taskと入力
  3. ユーザータスクを開くをクリック

task.jsonの編集

次の内容をtask.jsonにコピペする。

task.json

{
    // See https://go.microsoft.com/fwlink/?LinkId=733558
    // for the documentation about the tasks.json format
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Sass new project create",
            "type": "shell",
            "command": "/Users/tomixy/MyShellScript/MySassCreate.sh",
            "args": ["${input:SassProjectName}"],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
        {
            "label": "Sass compile",
            "type": "shell",
            "command": "cd ${fileDirname} && cd .. && sass ${file}:css/${fileBasenameNoExtension}.css --style expanded --sourcemap=none && cd css && npx postcss *.css --use autoprefixer -d ./ ",
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
    ],
    "inputs": [
        {
            "id": "SassProjectName",
            "description": "Sass new project name:",
            "default": "sample",
            "type": "promptString"
        }
    ],
}


MySassCreate.shのコード解説

シェバン

MySassCreate.shの一部

#!/bin/sh

『これはbashスクリプトですよ〜』とPCに宣言する部分。この記述のあるファイル名を黒い画面で入力+Enterすると、PCは自動的にbashでこのスクリプトを実行しようとする。

もしzshで実行したのなら、この部分は『これはbashスクリプトですよ〜、でもあなたはzshみたいね…まあいいわ、うまくやってあげる。』とPCに呼びかける意味合いになる。 Z ShellのWikiより、

zsh/bin/shとして実行したとき、Bourne Shellの振りをするようにできる。

bashBourne ShellzshはZ Shellの略らしいよ。

しかしシェルとはいえ、Power ShellではMySassCreate.shは実行できないと思われる。構文が結構違うらしい。

コマンドライン引数の取得

MySassCreate.shの一部

PROJECT=$1

/Users/tomixy/MyShellScript/MySassCreate.sh パッケージ名としてこのシェルスクリプトを実行するわけだが、このとき与えたパッケージ名$1に格納されている。
この定数を、これからはPROJECTと呼ぶよ〜という意味。

不思議なことに、PROJECT = $1としてはダメらしい。=の左右にスペースを空けてはいけません。

compassプロジェクト(npmパッケージとなるフォルダ)の作成

MySassCreate.shの一部

compass create $PROJECT

compass create フォルダ名で、指定したフォルダ内をSass作業用に整理してくれる。具体的には、次のような中身になる。

f:id:nix_campane:20210322125512p:plain
compass create sampleの実行例

私も詳しくは知らないが、

ie.css
Internet Exprorer対応のCSSを書くための雛形
print.css
印刷用のCSSを書くための雛形
screen.css
画面表示用の(つまり普通の)CSSを書くための雛形(CSSリセットの宣言つき)
config.rb
compassコマンドでのコンパイル用の設定を書いておくファイル


…らしい。

とはいえ、前述したようにcompassのサポートは既に終了しているので、ここで作られたie.cssを使ったところで最新のものに対応できるかはわからない。

シェルスクリプトでは、#以降は実行されない部分になる。よって、ここには何を書いても良い。
#!だけは例外なので注意。#!で始まるものはシェバンとして解釈されてしまう。

compassを使わない場合は、compass createの前に#を置く(コメントアウトする)ことでcompass createコマンドを無効化にする。 また、その場合はcompassが作るはずだったフォルダを手動で作成しなければならないため、# mkdir $PROJECTの先頭の#を取る(コメントインする)。

言い忘れていたが、シェルスクリプトでは、事前に宣言しておいた変数は$変数名で参照できる。

フォルダ内をWeb制作用にカスタマイズする

MySassCreate.shの一部

cd $PROJECT 

おそらく、今のカレントディレクトリは$PROJECTフォルダを置いた場所(つまり、$PROJECTフォルダの手前のフォルダ)になっていると思うので、cd $PROJECTでプロジェクトフォルダ内に移動する。

cd フォルダ名
指定したフォルダ内に移動

MySassCreate.shの一部

mkdir css

compassで自動作成した場合、拡張子が.cssのファイルがstylesheetsフォルダに格納されている。
わかりづらいので、拡張子が.cssのファイルはcssフォルダに格納されるようにしたい。そのために、まずはmkdir cssでプロジェクトフォルダ内にcssフォルダを作成する。

mkdir フォルダ名
今いるフォルダ内に指定した名前のフォルダを作成

MySassCreate.shの一部

cd stylesheets
rm -f ie.css
rm -f print.css
mv screen.css ../css

cd stylesheetsでstylesheetsフォルダ内に移動し、この中にあるie.cssとprint.cssは削除し、screen.cssは新たに作成したcssフォルダに移動させる。
../cssは、一つ前のディレクトリに戻って(stylesheetsディレクトリから出て)、その後cssディレクトリ内に入った場所を表す。

rm -f ファイル名
指定したファイルを削除(remove)する
-fは警告を表示せず処理を実行するためのオプション)
mv ファイル名 移動先フォルダのパス
指定したファイルを指定したフォルダに移動(move)させる


MySassCreate.shの一部

cd ..
rm -d stylesheets

cd ..で今いるstylesheetsフォルダから出て、stylesheetsフォルダを削除する。

cd ..
今いるフォルダから出る(一つ前のフォルダに戻る)
rm -d フォルダ(ディレクトリ)名
指定したディレクトリ(-d)を削除(remove)する

MySassCreate.shの一部

cd css
mv screen.css reset.css

cd csscssフォルダ内に移動し、mv screen.css reset.cssでscreen.cssをreset.cssに改名する。

mv ファイル名 変更後のファイル名
ファイル名を変更する

MySassCreate.shの一部

cd ../sass
rm -f *.scss
touch styles.scss
cd ..

cd ../sasscssフォルダから出たところにあるsassフォルダに移動する。

その後、rm -f *.scssでsassフォルダ内の全てのファイルを消去する。
*ワイルドカードといい、どんな文字列でもよいことを表す。つまり、*.scssは拡張子が.scssのすべてのファイルである。

touch styles.scssで空のファイルstyles.scssを作成し、cd ..でsassフォルダから出る。

touch ファイル名
指定した名前のファイルを作成する。このコマンドで作成したファイルの中には、何も書かれていない。

MySassCreate.shの一部

mkdir js
cd js
touch scripts.js
cd ..

mkdir jsでプロジェクトフォルダ内にjsフォルダを作成し、cd jsでjsフォルダ内に移動する。
touch scripts.jsで空のファイルscripts.jsを作成し、cd..でjsフォルダから出る。

MySassCreate.shの一部

mkdir images

プロジェクトフォルダ内にimagesフォルダを作成する。

MySassCreate.shの一部

touch index.html

プロジェクトフォルダ内に空のファイルindex.htmlを作成する。

task.jsonのコード解説

MySassCreate.shの実行

task.jsonの一部

    "tasks": [
        {
            "label": "Sass new project create",
            "type": "shell",
            "command": "/Users/tomixy/MyShellScript/MySassCreate.sh",
            "args": ["${input:SassProjectName}"],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ],
    "inputs": [
        {
            "id": "SassProjectName",
            "description": "Sass new project name:",
            "default": "sample",
            "type": "promptString"
        }
    ]

"tasks": [ ]

"label"では、shift ctrl Bmacならshift(⬆️) command B)を押した時に表示されるタスク名を設定する。

今回実行する

Run Command

/Users/tomixy/MyShellScript/MySassCreate.sh プロジェクト名

というコマンドはターミナルで実行するものなので、"type"shellとする。
引数であるプロジェクト名は、"args"で管理する。 ${input}は入力された文字列を表し、後の設定時に参照するために${input:id}という書式でid(名前)をつけておく。

"group"では、このタスクの分類を指定する。

"kind"には開発用タスクを表すbuildか、デバッグ用タスクを表すtestを指定することができる。今回は前者である。

shift ctrl Bmacならshift(⬆️) command B)を押したときにすぐに実行できるように、"isDefault": trueとしておく。

inputs: [ ]

idがSassProjectNameである入力引数の設定を行う。

"description"で何を入力すべきかの説明文を指定し、"default"でデフォルト入力値を設定する。

最終的にこのコマンドはターミナルで実行されるので、入力タイプはターミナルに表示する文字列であるpromptStringと指定する。

Sassコンパイルコマンドの設定

task.jsonの一部

          {
                "label": "Sass compile",
                "type": "shell",
                "command": "cd ${fileDirname} && cd .. && sass ${file}:css/${fileBasenameNoExtension}.css --style expanded --sourcemap=none && cd css && npx postcss *.css --use autoprefixer -d ./ ",
                "group": {
                    "kind": "build",
                    "isDefault": true
                }
            }

shift ctrl Bmacならshift(⬆️) command B)を押し、Sass compileを選択したときに実行されるコマンドは、次のものである。

"command"

cd ${fileDirname} && cd .. && sass ${file}:css/${fileBasenameNoExtension}.css --style expanded --sourcemap=none && cd css && npx postcss *.css --use autoprefixer -d ./ ",

&&を使うことで、複数のコマンドを一気に実行することができる。

コマンド1 && コマンド2
コマンド1が正常に実行されたら、コマンド2を実行する


&&で結ばれたコマンド一つ一つを見ていこう。

task.jsonで使える変数

${fileDirname}
task.jsonで使える変数で、今開いているファイルが置かれているディレクトリを表す。
${file}
task.jsonで使える変数で、今開いているファイルのパスを表す。
${fileBasenameNoExtension}
task.jsonで使える変数で、今開いているファイル名から拡張子を除いたものを表す。
今開いているファイルがstyles.scssなら、${fileBasenameNoExtension}stylesを表す。

コンパイルコマンドの解剖

cd ${fileDirname}
今はコンパイルしたいscssファイルを開いているはずなので、${fileDirname}はsassフォルダを表す。
つまり、sassフォルダ内に移動するという意味。
cd ..
sassフォルダから出て、プロジェクトフォルダに移動する。
sass コンパイルするファイル:コンパイル後のファイル
sassコマンドで、拡張子が.scssまたは.sassのファイルをコンパイルし、cssファイルに変換できる。
sass ${file}:css/${fileBasenameNoExtension}.css
コンパイルしたいファイルは今開いているファイルなので、${file}とする。
コンパイル後のファイルはcssフォルダ内に置きたいのでcss/をつけ、その中にコンパイル前のscssファイルと同名のcssファイル(${fileBasenameNoExtension}.css)として出力する。
--style expanded
コンパイル後のcssファイルの書式を一般的なものに指定するオプション。
他にもいろいろな書式にコンパイルすることができる。詳細を知りたい方はこのブログを読むのがオススメ。
--sourcemap=none
ソースマップファイルを出力しないためのオプション。cssフォルダの中にはcssファイルだけを入れておきたいので、このオプションを付与した。
cssが長文になる場合はこのオプションをつけない方が良い気がする。

他にもいろいろなオプションがある。その他のオプションや、ソースマップファイルの存在意義についてはこのブログを読むのがオススメ。

ベンダープレフィックス自動付与コマンドの解剖

cd css
コンパイル済みのcssファイルを改変するため、cssフォルダ内に移動する。
npx postcss *.css
postcssは、cssファイルを解析、改変するツール。ここでは解析対象をcssフォルダ内にあるすべてのcssファイルにしている。
--use autoprefixer
autoprefixerは、ベンダープレフィックスを自動付与するツール。
postcssによって解析したcssファイルにベンダープレフィックスを付与する。
-d ./
-dは、ベンダープレフィックス付与後のcssファイルの置き場所を指定するためのオプション。
.は今いるフォルダ(cssフォルダ)を表し、./とすることでcssフォルダ内にベンダープレフィックスが付加されたcssファイルが置かれることになる。
同名のファイルは自動的に置換されるので、結局は元のcssファイルを書き換えた事になる。

index.html編集用スペニットの登録

cssファイルやjsファイルを外部に配置すると、htmlファイル内でファイルを読み込むために必ず記述しなければならないコードが増えてしまう。
それをいちいち書くのも面倒なので、htmlファイルの雛形(スペニット)を作っておこう。

html.jsonの開き方

f:id:nix_campane:20210427085239p:plain
左下の設定ボタンをクリック

f:id:nix_campane:20210427085320p:plain
ユーザースペニットをクリック

f:id:nix_campane:20210427085358p:plain
すると、画面上部にこのようなパネルが表示される

f:id:nix_campane:20210427085435p:plain
htmlと入力し、html.jsonをクリック

html.jsonの編集

html.json{ }の中に、次のコードを追加し、保存する。

html.json


"external jQuery and JavaScript and CSS" : {
        "prefix": "exjQJSCSS",
        "body": [
              "<!DOCTYPE html>",
              "<html lang=\"ja\">",
              "<head>",
              "\t<meta charset=\"UTF-8\">",
              "\t<meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">",
              "\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">",
              "\t<title>$1</title>",
              "\t<link rel=\"stylesheet\" type=\"text/css\" href=\"css/reset.css\" />",
              "\t<link rel=\"stylesheet\" type=\"text/css\" href=\"css/${2:styles}.css\" />",
              "\t<script src=\"https://cdnjs.cloudflare.com/ajax/libs/jquery/${3:3.4.1}/jquery.min.js\"></script>",
              "\t<script src=\"js/${4:scripts}.js\"></script>",
              "</head>",
              "<body>",
              "\t$5",
              "</body>",
              "</html>"
        ]
    }

スペニットの威力

早速、登録したスペニットをindex.htmlで使用してみよう。

f:id:nix_campane:20210427093023p:plain
すると、スペニットが展開され、カーソルがtitleを入力する位置に来る

f:id:nix_campane:20210427093132p:plain
タイトルを入力してtabキーを押すと、今度はcssファイル名を変更するかを問われる

f:id:nix_campane:20210427093311p:plain
またtabキーを押すと、今度はjQueryのバージョンを変更するか問われる

f:id:nix_campane:20210427093411p:plain
またtabキーを押すと、今度はjsファイル名を変更するか問われる

f:id:nix_campane:20210427093512p:plain
またtabキーを押すと、body要素内部にカーソルが来る

読み込むcssファイルやjsファイルの名称は、MySassCreate.shでデフォルトで作成されるファイル名になっている。
特に変更する気がなければ、そのままtabキーを押すことでスキップできる。

また、jQueryは端末にダウンロードすることなく使えるように読み込んである。使用するバージョンは適宜変更してほしい。

私は今のところはデフォルトのまま使っていて支障がないので、タイトルを入力した後は4回tabキーを押し、すぐにbody内部の編集に取り掛かっている。

vscodeでのDart Sass開発環境構築、さらにシェルスクリプトで全自動化【Autoprefixer使用・Compass共存可】

WARMING

2021/4/19追記

この記事に掲載しているソースコードは、時々原因不明のエラーを吐きます。
改良版のソースコードこちらの記事にて公開しました。

この記事はSass環境構築の解説というよりも、npmやシェルスクリプト文法(特にパイプ)の解説としてご活用いただければ幸いです。

Webサイト制作本を何冊か読み、『先ほどのCSSをコピペして〜』という記述に若干の反発を感じ始めた頃、Sassの存在を知った。

Sassを使うと一般的なプログラミング言語のような分岐処理、繰り返し処理、演算などを使ってCSSを書くことができる。念願の脱コピペ。やっぱりみんな考えることは一緒だよね…

Compassの使用方針について

Compassのサポートは2016年に終了しているので、今から使い始めるのは推奨されていない。
この記事では、基本的に雛形作成(ディレクトリの整理整頓)のためだけにCompassを利用し、Compassを使わない場合にも似たようなディレクトリ構成が用意されるようにコードの修正点を明記していく。

Sassのコンパイルには、速度が遅いCompassコマンドは使用せず、これからも新機能が増築されていく最新のDart Sassを用いる。

しかし、どんどん新たなツールが生み出されているとはいえ、CSSスプライト作成機能など、未だCompassにしかない機能もいくつかあるらしい。そんなわけで、いつでもCompassも使えるように環境だけは残しておくことにする。

インストールするもの

Visual Studio Code(この記事では必須)
コードを編集するためのテキストエディタテキストエディタとは名ばかりで、実際のところこれ一つでなんでもできる統合開発環境
普通、統合開発環境といえば各言語専用だが、VScodeは本当になんでもできる。今のところ、C, C++, C#, Python, JavaScript, Ruby, HTML, CSS, Sass(Scss), LaTeX…などあらゆる言語をここで編集し、実行できている。
適当にググってカスタマイズしてほしい。
node.js(この記事では必須)
node.jsをインストールすると使えるようになるnpmコマンドがこの記事では(というかいろいろな場面で)必須になる。
インストール方法はOSによって異なるようなので、ググって…
Dart SassやAutoprefixerはPC本体には格納せず、npmコマンドでその都度ローカルインストール(自分で作ったSassコードなどと一緒に共有できるように作業ディレクトリにインストール)するので、Compassと共存させない場合はこれ以上のインストール作業は必要ない。
RubyCompassと共存させる場合)
Sassコードをコンパイル(ブラウザが認識可能なCSSに変換)するために必要。
Macは最初から入っているのでスルー。Windowsの方は申し訳ないがググって…
Sass(Compassと共存させる場合)
CSSプログラミング言語のように効率的に書ける言語。
黒い画面からgem install sassでインストールできるはず。Macの方はsudoを先頭につけて。
compassCompassと共存させる場合)
Sassで使える便利グッズ集(Sassのミックスインや関数をライブラリ化したもの)。Sassのコンパイラとしても使える。
黒い画面からgem install compassでインストールできるはず。Macの方はsudoを先頭につけて。
autoprefixer-railsCompassと共存させる場合)
CSSベンダープレフィックス(ブラウザごとの表示の差異をなくすために必要なコード)を自動で追加してくれるツール。
黒い画面からgem install autoprefixer-railsでインストールできるはず。Macの方はsudoを先頭につけて。
csso-railsCompassと共存させる場合)
CSS縮小化ツール。別に入れなくてもよさそうだけど一応…
黒い画面からgem install csso-railsでインストールできるはず。Macの方はsudoを先頭につけて。

npmの意義

npmでは一つのアプリケーションを構成するソースファイルetc.を集めたフォルダをパッケージという。

ここではあえてソースファイルetc.と書いた。
npmの凄いところは、自分で書いたソースファイルだけでなく、それをコンパイルするコンパイラなども含めて一つのアプリケーションとしてまとめられるところだ。

例えば、作ったアプリケーションを人に提供するとき、中身がHTML, CSS, Javascriptのみであれば、相手のPCでもすぐにブラウザで実行できるだろう。
しかし、TypeScriptで書かれたファイルなどは、JavaScriptコンパイルしなければ実行できない。相手にわざわざ『TypeScriptのコンパイラをインストールしておいてね』と伝えなくてはならない。これは面倒くさい。

そこでnpmが活躍する。npmでは、ローカルインストールという機能によって、コンパイラなどを好きなディレクトリにインストールすることができる。
アプリケーションをコンパイラとセットで相手に渡せば、相手の環境にかかわらずそれを実行できる。
また、コンパイルのためのコマンドは、オプション指定などで長くなることも多い。npmでは、それらのコマンドを短いコマンドに置き換えられるように、そのパッケージ専用の独自のコマンドを設定することができる。

これから行う工程の目的はこれくらいで理解できるはず。もっと詳しく学びたい方にはこちらの記事をお勧めしておく。(まだ私も読んでいる途中)

Dart Sassをコンパイルするまでの道のり

さて、新しいnpmパッケージを作成してSassをコンパイルするまでの道のりは、結構面倒なものである。

  1. パッケージの雛形を作成
  2. パッケージ内にSassをローカルインストール
  3. package.jsonに自作コンパイルコマンドを追加

これに加えて、パッケージ内で、拡張子が.scsssassのファイルはsassフォルダに収納し、それをコンパイルして得られる拡張子が.cssのファイルはcssフォルダに吐き出されるように設定したい。
(これはcompassプロジェクトとして作成した雛形を少し書き換えてそれをnpmパッケージとして登録すれば容易に実現できるが、compassを使わない方法も紹介する。)

また、CSSベンダープレフィックス(ブラウザごとの表示の差異を埋めるための追加コード)を自動で書き加えるためのツールを導入した方が良い。

これらの作業を、新たなディレクトリでSassを書くたびに行うのか?

…それは面倒くさすぎるので、自動化ツールを作りました。

Sassを使う環境(npmパッケージ)作成の自動化

初期設定

下のMySassCreate.shMyConfig.rbを同じディレクトリにコピーしてね。

参考までに、私はホームディレクト/Users/tomixyMyShellScriptというフォルダを作って、その中にMySassCreate.shとMyConfig.rbを置いている。
置き場所に応じて、以降登場する/Users/tomixy/MyShellScript/をそのディレクトリ名に書き換えてね。

macの方はchmod u+x /Users/tomixy/MyShellScript/MySassCreate.shを実行するのを忘れずに。これを実行しないとMySassCreate.shは動きません。

実行方法

  1. 黒い画面を開く
  2. Windowsならbashコマンドでbashを起動
  3. パッケージ(作業ディレクトリ)を作りたい場所にcdコマンドで移動
  4. /Users/tomixy/MyShellScript/MySassCreate.sh パッケージ名を実行

すると、次のようなフォルダが生成される。

f:id:nix_campane:20210322104246p:plain
例として、パッケージ名はsampleとした。

自動化シェルスクリプトMySassCreate.sh全文

zshでしか動作確認していないが、bashでも使えるはず。(というかそもそもbashのためのコード)
windowsの方は…そうだなあ。私はwindows時代、この記事を見ながらbashを導入した気がする。

あ、そうだ忘れてた…jqをインストールしておかないと動かないので注意。
macならsudo brew install jqでインストールできるけど…OSによって違うのでjq インストール OS名と検索。

MySassCreate.sh

#!/bin/sh

PROJECT=$1

compass create $PROJECT # compassを使わない場合はコメントアウト
# mkdir $PROJECT # compassを使わない場合はコメントイン
cd $PROJECT 
# mkdir sass # compassを使わない場合はコメントイン
mkdir css

# compassを使わない場合は下の5行をコメントアウト
cd stylesheets
mv *.css ../css
cd ..
rm -d stylesheets
cp -f /Users/tomixy/MyShellScript/MyConfig.rb config.rb

npm init -y
npm install sass fibers --save-dev
npm install postcss postcss-cli autoprefixer --save-dev 

cat package.json|jq '.scripts += {"start": "sass sas$FILENAMEscss:css/$FILENAME.css --style expanded --watch | postcs--useautoprefixer -b \"last 10 versions\" css/$FILENAME.css -css$FILENAME.css "}' > package.txt
cat package.txt > package.json
rm -f package.txt

細かく解説

※ここからしばらくはコードの解説なので、早く実行したい人はここに飛んでね

シェバン

MySassCreate.shの一部

#!/bin/sh

『これはbashスクリプトですよ〜』とPCに宣言する部分。この記述のあるファイル名を黒い画面で入力+Enterすると、PCは自動的にbashでこのスクリプトを実行しようとする。

もしzshで実行したのなら、この部分は『これはbashスクリプトですよ〜、でもあなたはzshみたいね…まあいいわ、うまくやってあげる。』とPCに呼びかける意味合いになる。 Z ShellのWikiより、

zsh/bin/shとして実行したとき、Bourne Shellの振りをするようにできる。

bashBourne ShellzshはZ Shellの略らしいよ。

しかしシェルとはいえ、Power ShellではMySassCreate.shは実行できないと思われる。構文が結構違うらしい。

コマンドライン引数の取得

MySassCreate.shの一部

PROJECT=$1

/Users/tomixy/MyShellScript/MySassCreate.sh パッケージ名としてこのシェルスクリプトを実行するわけだが、このとき与えたパッケージ名$1に格納されている。
この定数を、これからはPROJECTと呼ぶよ〜という意味。

不思議なことに、PROJECT = $1としてはダメらしい。=の左右にスペースを空けてはいけません。

compassプロジェクト(npmパッケージとなるフォルダ)の作成

MySassCreate.shの一部

compass create compass create $PROJECT # compassを使わない場合はコメントアウト
# mkdir $PROJECT # compassを使わない場合はコメントイン

compass create フォルダ名で、指定したフォルダ内をSass作業用に整理してくれる。具体的には、次のような中身になる。

f:id:nix_campane:20210322125512p:plain
compass create sampleの実行例

私も詳しくは知らないが、

ie.css
Internet Exprorer対応のCSSを書くための雛形
print.css
印刷用のCSSを書くための雛形
screen.css
画面表示用の(つまり普通の)CSSを書くための雛形(CSSリセットの宣言つき)
config.rb
compassコマンドでのコンパイル用の設定を書いておくファイル


…らしい。

とはいえ、前述したようにcompassのサポートは既に終了しているので、ここで作られたie.cssを使ったところで最新のものに対応できるかはわからない。

シェルスクリプトでは、#以降は実行されない部分になる。よって、ここには何を書いても良い。
#!だけは例外なので注意。#!で始まるものはシェバンとして解釈されてしまう。

compassを使わない場合は、compass createの前に#を置く(コメントアウトする)ことでcompass createコマンドを無効化にする。 また、その場合はcompassが作るはずだったフォルダを手動で作成しなければならないため、# mkdir $PROJECTの先頭の#を取る(コメントインする)。

言い忘れていたが、シェルスクリプトでは、事前に宣言しておいた変数は$変数名で参照できる。

パッケージ内のフォルダをカスタマイズする

MySassCreate.shの一部

cd $PROJECT 
# mkdir sass # compassを使わない場合はコメントイン
mkdir css

# compassを使わない場合は下の5行をコメントアウト
cd stylesheets
mv *.css ../css
cd ..
rm -d stylesheets

おそらく、今のカレントディレクトリは$PROJECTフォルダを置いた場所(つまり、$PROJECTフォルダの手前のフォルダ)になっていると思うので、cd $PROJECTでパッケージフォルダ内に移動する。

compassを使わなかった場合は、まだsassフォルダもcssフォルダも作成されていないので、mkdirコマンドで作成する。

compassで自動作成した場合は、拡張子が.cssのファイルがstylesheetsフォルダに格納されている。
わかりづらいので、stylesheetsフォルダは削除し、新規に作成したcssフォルダに中身を移すことにする。

cd stylesheets以降はこの移行作業になるので、compassを使わない場合はコメントアウトで無効化した方が良い。

cd stylesheetsでstylesheetsフォルダ内に移動し、中のファイルをcssフォルダ内に移動する。
*ワイルドカードといい、どんな文字列でもよいことを表す。つまり、*.cssは拡張子が.cssのすべてのファイルである。
../cssは、一つ前のディレクトリに戻って(stylesheetsディレクトリから出て)、その後cssディレクトリ内に入った場所を表す。

mv *.css ../css
すべてのcssファイル(*.css)をcssディレクトリ(../css)にmoveする
cd ..
cssディレクトリから出る(一つ前のディレクトリに戻る)
rm -d stylesheets
stylesheetsというディレクトリ(-d)を削除(remove)する


compassコマンドによるコンパイルの設定をする

compass createコマンドによって作られたconfig.rbファイルの中身はデフォルトのものである。 これをカスタマイズしたものをMyConfig.rbとし、これをそっくりそのままconfig.rbにcopyする。

MySassCreate.shの一部

cp -f /Users/tomixy/MyShellScript/MyConfig.rb config.rb

デフォルトのconfig.rb

require 'compass/import-once/activate'

http_path = "/"
css_dir = "stylesheets"
sass_dir = "sass"
images_dir = "images"
javascripts_dir = "javascripts"

compass設定ファイルの雛形のMyConfig.rb

require 'compass/import-once/activate'

# compassコマンドによるコンパイルでもベンダープレフィックスを使用するための設定
require "autoprefixer-rails"
require "csso"
on_stylesheet_saved do |file|
  css = File.read(file)
  File.open(file, "w") do |io|
    io << AutoprefixerRails.process(css, browsers: ["> 1%", "last 2 versions", "ie 10"])
  end
end

http_path = "/"
css_dir = "css" # 新規に作ったcssフォルダにcssファイルが出力されるようにする
sass_dir = "sass"
images_dir = "image"
javascripts_dir = "js"

# その他の設定
output_style = :expanded
relative_assets = true
line_comments = false

ベンダープレフィックスの設定は、このブログから丸ごとコピペした。
その他の設定については、このブログを参考に選択した。

npmパッケージを作成

MySassCreate.shの一部

npm init -y

これで$PROJECTフォルダ内にpackage.jsonファイルやnode_modulesフォルダが作成される。package-look.jsonファイルも作成されているかも。
npm initコマンドを実行すると、途中でパッケージの設定についていろいろと質問されるが、それらをすべてスキップしてデフォルト値を埋め込むために-yオプションをつけている。

Sassコンパイラなどをnpmでローカルインストール

MySassCreate.shの一部

npm install sass fibers --save-dev
npm install postcss postcss-cli autoprefixer --save-dev

npm install パッケージ名
カレントディレクトリにパッケージをローカルインストールする
fibers
よくわからないが、速くインストールするために処理の仕方を変えるオプション
--save-dev
インストールしたパッケージを、package.jsonに依存パッケージ(これがないとこのアプリは動かないよ!というパッケージ)として記述するオプション。
依存パッケージがアップデートすると今まで使えていたコマンドなどが使えなくなり、コードの修正が必要になることもある。依存パッケージをpackage.jsonに書いておくと、npm側でいろいろな管理処理をしてくれるらしい。
PostCSS
CSSを変換するツール
postcss-cli
PostCSSを黒い画面で使えるようにするツール
Autoprefixer
PostCSSによってベンダープレフィックスを追加するツール

package.jsonの修正点

JSONは、簡単にいえば{ key : value }という形で表されたデータの集まりである。

npm init -yコマンドによりデフォルトで作成されるpackage.jsonは、次のようになっている。

デフォルトのpackage.json

{
  "name": "$PROJECT",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

このファイルを自動で次のように書き換えることを目指す。(scriptsインデックスの値に"start":"コンパイルコマンド"を追加した)

修正後のpackage.json(イメージ)

{
  "name": "$PROJECT",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" &exit 1",
    "start":"コンパイルコマンド"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

コンパイルとベンダープレフィックス付加を一気に行うコマンドを作成

コンパイルコマンドとだけ示した部分には、次のコードが入る。 ($filenameは、コンパイルコマンド実行時に渡す引数)

コンパイルコマンド

sass sass/$FILENAME.scss:css/$FILENAME.css --style expanded --watch | postcss --use autoprefixer -b \"last 10 versions\" css/$FILENAME.css -o css/$FILENAME.css
sassコマンドについて
sass
拡張子が.scss、.sassのファイルをコンパイル(.cssファイルに変換)するコマンド
sass sass/$FILENAME.scss:css/$FILENAME.css
sass コンパイルするファイル:コンパイル後のファイル
--style expanded
コンパイル後のCSSファイルの書式をexpanded(わかりやすいブログはこちら)に設定
--watch
以後、黒い画面を開いている間は保存する度にコンパイルを実行してCSSファイルを更新する
postcssコマンドについて
postcss ファイル名.css
引数として指定したCSSファイルを解析
--use autoprefixer
postcssでautoprefixerを使うオプション
-b "last 10 versions"
10バージョン前のブラウザまで対応
-o ファイル名
指定したファイルに改変後のCSSを出力
シェルスクリプトにおけるパイプ|
コマンドA | コマンドB
コマンドAを実行し、その標準出力をコマンドBの引数としてコマンドBを実行
標準出力
黒い画面に吐き出されたテキストのこと


コマンドAがファイルの中身を黒い画面に表示するというものなら、表示されたファイルの中身をコマンドBで加工するということになる。

ただし、sassコマンドは.cssファイルを作成するだけで、黒い画面には何も表示しない。このままではpostcssの引数は空であり、エラーになってしまうので、postcssにはcss/$FILENAME.cssという引数をわざわざ渡している。

コマンドBにあたる部分である次のコード

コマンドB

postcss --use autoprefixer -b \"last 10 versions\" css/$FILENAME.css -o css/$FILENAME.css

を解体すると、コマンド本体がpostcss、引数がcss/$FILENAME.css、オプションが--use autoprefixer-b \"last 10 versions\"-o css/$FILENAME.cssということになる。

このように、コマンドAが表示系のコマンドではなく、コマンドBに明示的に引数を渡している場合、パイプ|はただ単にコマンドAを実行した後にコマンドBを実行するという意味の記号として使われている。

コマンドを書き加えたjsonテキストを一旦package.txtに吐き出す

MySassCreate.shの一部

cat package.json|jq '.scripts += {"start": "sass sass/$FILENAME.scss:css/$FILENAME.css --style expanded --watch | postcss --use autoprefixer -b \"last 10 versions\" css/$FILENAME.css -o css/$FILENAME.css "}' > package.txt

もっとわかりやすく表すと、

MySassCreate.shの一部

cat package.json | jq '.scripts += {"start": " さっきのコマンド "}' > package.txt
cat ファイル名
ファイルの中身を黒い画面に表示する
表示系コマンド > ファイル
コマンドの結果を黒い画面に表示するのではなく、ファイルに書き出す
jq '処理' JSON形式のファイル
JSON形式のファイルの中身を取得し、指定された処理をして、黒い画面に表示
.KEY
インデックスがKEYである要素{ "KEY" : "value" }
.KEY += { ITEM }
インデックスがKEYである要素{ "KEY" : value }のvalueの部分にITEMを追加して、要素全体を書き換える


jqコマンドの引数は一見存在しないかのように見える。
しかし、catが表示コマンドであるので、catで表示したファイルの中身をそのままjqコマンドに渡していることになる。
引数として渡されたpackage.jsonのデータを、jqコマンドで処理する。

jq '.scripts += {"start": " コンパイルコマンド "}' package.json > package.txtでも.jsonファイルは正しく作成されるが、コンパイルコマンドの実行時になぜかコンパイル不良が頻出するので、没とした。
おそらくテキストをそのままjqで処理させるのではなく、catコマンドでテキストをリスト化してからjqで処理させた方がいいのだろう。
どちらにしてもシェルスクリプトは原因不明の不具合が日常茶飯事らしいので、スマートなコードを目指すよりも経験的にうまくいく方法をとった方がよさそう。

jq '.scripts += {"start": ""sass sass/$FILENAME.scss:css/$FILENAME.css --style expanded --watch | postcss --use autoprefixer -b \"last 10 versions\" css/$FILENAME.css -o css/$FILENAME.css"}'というコマンドによって、インデックスがscriptsである要素は次のように変わる。

BEFORE

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  }

AFTER

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "sass sass/$FILENAME.scss:css/$FILENAME.css --style expanded --watch | postcss --use autoprefixer -b \"last 10 versions\" css/$FILENAME.css -o css/$FILENAME.css "
  }

そして、上のようにscriptsの値を書き換えたものを、本来なら黒い画面に表示するわけだが、代わりに> packge.txtによってpackage.txtファイルに書き出すことになる。

最初からpackage.jsonに吐き出せばいいのでは?と思うかもしれないが、そうするとpackage.jsonの中身は空になってしまう。この記事に書かれてあるように、直接package.jsonに上書きするのは原理的に不可能なようだ。

package.txtの中身

{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "sass sass/$FILENAME.scss:css/$FILENAME.css --style expanded --watch | postcss --use autoprefixer -b \"last 10 versions\" css/$FILENAME.css -o css/$FILENAME.css "
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "autoprefixer": "^10.2.5",
    "fibers": "^5.0.0",
    "postcss": "^8.2.8",
    "postcss-cli": "^8.3.1",
    "sass": "^1.32.8"}
  }
}

package.txtの中身をpackage.jsonにコピーする

MySassCreate.shの一部

cat package.txt > package.json
rm -f package.txt

cat package.txt > package.jsonによって、package.txtの中身を黒い画面に表示する代わりに、package.jsonに吐き出す。 このとき、元々のpackage.jsonの内容は消去され、完全に上書きされる。

一時的なデータ保管用であったpackage.txtはもう不要なので、rm -f package.txtで削除する。 『削除していいのですか?』的な確認メッセージが出ると、それに回答する手間が生じるので、確認メッセージを表示しないために-fオプションをつけておく。

作成した自動化ツールの使い方

初期設定が済んでいることを前提で話を進めます。

あと、VScodeユーザーならこの章は読むだけ無駄です。ここに進むことをおすすめします。

SassやCSSを作成するフォルダの作成

実行方法に書かれてある通りなので略。

Sassを書く

さっき作ったフォルダの中の、sassフォルダの中にオリジナルの.scssファイル(または.sassファイル)を追加していってね

Sassのコンパイル

  1. cdコマンドでsassファイルの中へ移動
  2. FILENAME=コンパイルしたいファイル名 npm run startコマンドを実行

startというのがpackage.jsonで定義したコンパイルコマンドだが、このコマンドに直接引数を渡すことは不可能なので、FILENAMEという定数を事前に定義して、それをコマンド内で参照する手段をとっている。

cssフォルダを覗いてみると、コンパイルしたかったファイルと同名の.cssファイル(と.css.mapファイル)が作成されているはず。ベンダープレフィックスも自動で追加されています!!

なお、このコマンドの実行以降は、sassファイルをいじって再保存したり、新たなsassファイルを作って保存したりすると、勝手にコンパイルされてcssフォルダ内が更新されていくよ。黒い画面を閉じない限りね!!

…って、これだとまだ面倒臭いじゃん

…と思いませんでした?

VScodeユーザーなら、ワンクリックでできるようになります!!

VScodeで簡単にパッケージ作成&Sassコンパイルできるようにする

初期設定

task.jsonを開く

  1. shift ctrl Pmacならshift(⬆️) command P
  2. taskと入力
  3. ユーザータスクを開くをクリック

開かれたtask.jsonに次の内容をコピペ

task.json

{
    "version": "2.0.0",
    "tasks": [
        {
            "label": "Sass new project create",
            "type": "shell",
            "command": "/Users/tomixy/MyShellScript/MySassCreate.sh",
            "args": ["${input:SassProjectName}"],
            "problemMatcher": [],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        },
        {
            "label": "Sass compile & watch start",
            "type": "shell",
            "command": "cd ${fileDirname} && cd .. && FILENAME=${fileBasenameNoExtension} npm run start",
            "problemMatcher": [],
            "group": {
                "kind": "build",
                "isDefault": true
            }
        }
    ],
    "inputs": [
        {
            "id": "SassProjectName", // ${input:***}で指定したID
            "description": "Sass new project name:", // 入力説明文
            "default": "sample", // デフォルト入力値
            "type": "promptString" // 入力タイプ
        }
    ],
}

使い方

SassやCSSを作成するフォルダの作成

  1. shift ctrl Bmacならshift(⬆️) command B
  2. Sass new project createをクリック
  3. 作成したいフォルダ名を入力(デフォルトではsample)

Sassを書く

さっき作ったフォルダの中の、sassフォルダの中にオリジナルの.scssファイル(または.sassファイル)を追加していってね

Sassのコンパイル

  1. shift ctrl Bmacならshift(⬆️) command B
  2. Sass compile & watch startをクリック

cssフォルダを覗いてみると、コンパイルしたかったファイルと同名の.cssファイル(と.css.mapファイル)が作成されているはず。ベンダープレフィックスも自動で追加されています!!

これ以降はsassファイルをいじって再保存したり、新たなsassファイルを作って保存したりすると、勝手にコンパイルされてcssフォルダ内が更新されていくよ。

あとがき

この自動化を実現するために初めてきちんとシェルスクリプトを勉強したので、ほぼほぼシェルスクリプト文法のアウトプットブログになってしまった。

実は、ブログに載せるために何度もテストしていく中で、MySassCreate.shに重大な欠陥があることに気がついた。もちろん修正済みのものを掲載している。ブログにまとめること自体がデバッグ作業。 それにしても、その欠陥というものは他の言語であれば即エラーを吐き出すようなヤバいものだった。あんなコードで動いてしまうシェルスクリプトって怖い。

実を言うとSassの勉強はまだしていないので、これからいろいろコンパイルしていく中でエラーが出る可能性も…そうしたらまたこの記事を修正しよう。安定して動作できることがある程度確認できたらGitHubにも載せる。

task.jsonの書き方についてもいつか追記するかも。とりあえず疲れたからこれでおしまい。

pyファイルの実行を極限まで楽にする【Python用のcode runnerショートカット改造】

code runnerを使えば、pyファイルもCtrl + Alt + Nで瞬時に実行できる。…が、その前にcdコマンドなどで実行したいファイルのあるディレクトリまで移動しておかなければならない。

いちいち手動で移動するのは面倒くさいので、Ctrl + Alt + Nショートカットにディレクトリ移動も組み込んでしまおう、というお話。

前提とする環境

  • pythonコマンドが使える
  • code runnerをインストール済み

ショートカット作成方法

setting.jsonを開き、"code-runner.executorMap":{}内の"python": "なんちゃら"

"python": "cd $dirWithoutTrailingSlash ; python $fileName"

に変更する。(beforeafter)

環境によってはpythonじゃなくてpython3かも。 PowerShell等でpythonもしくはpython3と入力+Enterしてみて、エラーにならずにPythonのバージョン情報が表示された方を当てはめて。

簡単に解説

実行したい(今VScodeで開いている)pyファイルのフルパスがkonofolderniaruyo/jikkositai.pyだとすると、

  • $dir ...konofolderniaruyo/
  • $dirWithoutTrailingSlash ...konofolderniaruyo
  • $fileName ...jikkositai.py

として置き換えられる。

つまり、cdコマンドでkonofolderniaruyoディレクトリに移動した後に、pythonコマンドでjikkositai.pyを実行するということ。

移動と実行という2つの操作を続けて行うことを;で表している。(&&-andだとなぜかエラーが出た)

csファイルだってcode runnerで一発コンパイルしたい!【C#用のcode runnerショートカット】

本来、code runnerはCtrl + Alt + Nでコンパイル・実行できることが最大のメリットなわけだが、どうやらC#ではそうもいかないらしく。 code runnerの初期設定では、CSscriptをインストールしておけばcsxファイルならCtrl + Alt + Nで実行できるとかなんとか。 どちらにせよ、csファイル(というかcsprojファイル)をビルド・実行するには、cdコマンドでビルドしたいcsprojファイルがあるフォルダーに移動した後に、dotnet runコマンドを手打ちする必要がある。

いちいちPowerShellcd ビルドしたいcsprojがある階層のフルパス + dotnet run と打ち込んでビルドするのは面倒臭いので、ショートカットを作成してしまおうというお話。

前提とする環境

  • dotnet runコマンドが使える
  • code runnerをインストール済み

ショートカット作成方法

setting.jsonを開き、"code-runner.executorMap":{}内の"csharp": "scriptcs""csharp": "cd $dir && dotnet run" に変更する。(beforeafter)

すると、Ctrl + Alt + Nで今開いているcsファイルのビルドができるようになった。

よくわからないが、

という2つの操作を続けて行うことを&&で表す

という意味合いっぽい。

効率化された試し割りによる素数判定【細かすぎるコード解説:C言語編】


14622回の除算で1000以下の素数を求める

手がかり

  •  2 以外の素数はすべて奇数
  •   1以外の正の整数はどれも素数の倍数といえる(素因数分解
  • 素数nで割り切れない整数は、nより大きいnの倍数でも割り切れない

 1 nでしか割り切れない整数 n素数)を探すとき、それより小さい素数で割り切れないものは、その他の整数(素数の倍数)でも割り切れない。

そのため、より小さいすべての素数で割ってみて割り切れるかのみ調べればよい。

プログラムのソースコード【細かすぎる注釈つき】

#include <stdio.h>

int main(void)
{
    //2以上1000以下の整数をnと表すことにする
    //つまり、整数nの中から素数を探すことになる
    int n;

    //除算回数を数えるカウンターを用意
    unsigned long counter=0;/*unsigned long…長い桁数の非負整数を格納できる箱の名称(型)*/

    //素数を入れる箱を500個用意する
    //2以外の素数はすべて奇数であり、1から1000までの数の中に奇数は500個しかない
    //そのうち1は素数ではなく、代わりに2は素数であるから、
    //結局素数を入れる箱は500個で足りる
    int prime[500];

    //i番目の素数をprime[i]と表すことにする
    int i;

    //既に見つけた素数の個数をptrとする。現時点ではまだ0である
    int ptr=0;

    //2と3は素数である
    prime[ptr++]=2;/*prime[0]=2と記憶した後に、ptrの値を1つ増やす(見つけた素数の個数が1になる)*/
    prime[ptr++]=3;/*prime[1]=3と記憶した後に、ptrの値を1つ増やす(見つけた素数の個数が2になる)*/

    //このように、小さい数から順に素数を探していくから、
    //番号が若い素数の方が小さい素数である

    //現時点で見つかっている素数2個(prt=2)のうち最大のものはprime[1]=3であるように、
    //これまで見つけたptr個の素数のうち最大のものは、prime[ptr-1]で表される

    //5以上1000以下の数の中から素数を探す
    for (n=5 ; n <= 1000; n+=2)/*5から始まって2ずつ増やしていくことで、奇数のみが対象になる*/
    {
        //これまで見つけた素数prime[0]~prime[ptr-1]すべてで割ってみる
        //しかし、これから見つける素数はすべて奇数であるので、2で割り切れる数(偶数)は最初から除外してよい
        //よってprime[0]である2で割る必要はないので、3=prime[1]~prime[ptr-1]で割ってみる
        for ( i = 1; i < ptr; i++)
        {
            counter++;/*除算回数が1増える*/

            if (n % prime[i] ==0)/*もし整数n(>4)がそれより小さい素数で割り切れたなら*/
            {
                break;           /*nは素数ではないので、もう他の数で割る必要はない⇒このforから追放*/
            }

            //ここでi++が実行され、iの値が1増える

            //割り切れなかったものはこのforの冒頭に戻り、iが1大きな値に書き換えられたforの中身を繰り返す
            //                                       (つまりより大きい素数で割られる)

        }
        
        //途中でforを追放されたものはここに到達している
        //まだiの値がptrよりはるかに小さい段階で中断されているので、
        //ptr=iという条件を満たさず、if(ptr==1){}はスルーしてこのまま外側のforからも抜けることになる

        //最大素数prime[ptr-1]までのすべての素数で割り切れなかったものは、
        //最後までbreakで抜けることなく、後処理i++を受けてここに到達する
        //つまり、最大素数での最後の除算をする段階ではi=ptr-1だが、その後のi++によって今はi=ptrとなっている
        //これは次のif文も実行されることになる

        if (ptr == i)/*i=ptrなら(これまで見つけたprime[ptr-1]までのすべての素数で割り切れなかったら)*/
        {
            prime[ptr++]=n;/*そんな整数nを新たな素数prime[ptr]として登録する
                            *(登録した後に、登録済み素数の数が1増える)       */
        }

        //ここでn+=2が実行され、nの値が2増える
        //外部forの冒頭に戻り、2大きな整数nについて全体の処理が再度行われる
        //このようにして、1000以下の整数をすべて登録済み素数で割って、選別する
        
    }

    //1000以下の整数すべての選別が終わると、ここに到達する
    //最終的に登録された素数すべて(prime[1]~prime[ptr-1])を一覧で表示する
    for ( i = 0; i < ptr; i++)
    {
        printf("%d\n",prime[i]);
    }
    
    //除算回数を表示する
    printf("乗除を行った回数:%lu\n",counter);

    return (0);
 }

3774回の乗算・除算で1000以下の素数を求める

強力な武器

改良版プログラムのソースコード【細かすぎる注釈つき】

変更した箇所にのみ補足説明を加えている。

#include <stdio.h>

int main(void)
{
    int n;

    //乗算・除算回数を数えるカウンターを用意
    unsigned long counter=0;

    int prime[500];

    int i;

    int ptr=0;

    prime[ptr++]=2;
    prime[ptr++]=3;

    for (n=5 ; n <= 1000; n+=2)
    {
        //2つの状態のどちらか(ONかOFFか)を判定するために使う変数をフラグという
        //今回は割り切れたか否かを判定する用に使う
        int flag = 0;/*初期値は0(フラグを下ろしておく)*/

        //nの平方根以下のすべての素数で割ってみる
        //『素数pがnの平方根以下』という条件は、両辺2乗して『pの2乗がn以下』と言い換えられる
        for ( i = 1; counter++ , prime[i]*prime[i] <= n; i++)
                     /*《A,B …AとBを順に実行し、Bの値を返す》
                      *for内部を実行するかの判定をするのはprime[i]*prime[i] <= nだが、
                      *判定の度に乗算*をカウントするということ             */
        {
            counter++;

            if (n % prime[i] ==0)/*割り切れたなら*/
            {
                flag = 1;        /*フラグを上げる*/
                break;           
            }

        }

        if (!flag)         /*flag=0(フラグが下がったまま)なら*/
        {
            prime[ptr++]=n;/*割り切れなかったということなので、素数として登録*/
        }
        
    }

    for ( i = 0; i < ptr; i++)
    {
        printf("%d\n",prime[i]);
    }
    
    printf("乗除を行った回数:%lu\n",counter);

    return (0);
 }

コード引用元

今回掲載したコードのベースとなっているのは、柴田望洋先生の著書明解C言語入門編の109・111ページに掲載されているサンプルコードです。 説明の都合上、変数の名称や変数宣言の順序を変えています。また、括弧のレイアウトは自分好みに変えています。

定理の証明に関する参考文献

現在LaTeXで制作中の整数論ノートに今回素数判定に用いた定理の証明も掲載予定です。 厳密な証明ではないですが、コード引用元の書籍では正方形の図によってわかりやすく導出されています。 厳密な証明を追いかけたい方にはモノグラフ 整数をオススメします(が、絶版なんだよなあ…)。

LaTeXで使える付箋風の枠【tcolorboxの可能性】

tcolorboxのマニュアルの8.3節にある作例にちょっとだけ手を加えたら、思いがけず可愛らしい付箋のような枠が生まれたので記録しておく。

コード全文

\usepackage[dvipdfmx]{graphicx,color}%オプションは一例
\usepackage{xcolor}

\usepackage{tikz}
\usetikzlibrary{calc}%座標を使って図形を描くために必要

\usepackage{xparse}%オプション(省略可能引数)をもつコマンド作成

\usepackage{tcolorbox}
\tcbuselibrary{listings,breakable,xparse,skins,hooks}
 %listings…私の環境ではbreakableを使う際に必要
 %breakable…ページまたぎ可能な枠を作成できる
 %xparse…オプションをもつ枠を作成できる
 %skins…TikZで枠のデザインを描き足せる
 %hooks…多種多様な機能が含まれるため、とりあえず読み込んでおくと安全
 %           たとえばunderlay unbrokenに必要
 
%付箋環境~水色バージョン~の定義
\DeclareTColorBox{fusenmz}{m O{} }%
{enhanced,
 colframe=white,
 colback=yellow!10!white,
 coltitle=cyan!40!black, 
 fonttitle=\bfseries,breakable,
 underlay unbroken={\begin{tcbclipinterior}
                             \shade[inner color=cyan!80!yellow,outer color=yellow!10!white] (interior.north east) circle (2cm);
                             \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                           \end{tcbclipinterior}}, 
 underlay first={\begin{tcbclipinterior}
                       \shade[inner color=cyan!80!yellow,outer color=yellow!10!white] (interior.north west) circle (2.5cm);
                       \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                    \end{tcbclipinterior}}, 
 underlay last={\begin{tcbclipinterior}
                       \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                    \end{tcbclipinterior}}, 
 title={#1},
 attach title to upper=\quad, #2
}

%付箋環境~桃色バージョン~の定義
\DeclareTColorBox{fusenmm}{m O{} }%
{enhanced,
 colframe=white,
 colback=yellow!10!white,
 coltitle=magenta!40!black, 
 fonttitle=\bfseries,
 breakable,
 underlay unbroken={\begin{tcbclipinterior}
                             \shade[inner color=magenta!80!yellow,outer color=yellow!10!white] (interior.north east) circle (2cm);
                             \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                          \end{tcbclipinterior}}, 
 underlay first={\begin{tcbclipinterior}
                       \shade[inner color=magenta!80!yellow,outer color=yellow!10!white] (interior.north west) circle (2.5cm);
                       \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                    \end{tcbclipinterior}}, 
 underlay last={\begin{tcbclipinterior}
                       \draw[help lines,step=5mm,yellow!80!black,shift={(interior.north west)}] (interior.south west) grid (interior.north east);
                    \end{tcbclipinterior}}, 
 title={#1},
 attach title to upper=\quad, 
 #2
}

使用法

%fusenmzの場合も同様
\begin{fusenmm}{タイトル}[さらなるtcolorboxのオプション]
テキスト
\end{fusenmm}

使用例ギャラリー

%プリアンブルに追加
\usepackage[math]{anttor}%オシャレな数式・英文フォント
\usepackage{enumerate}

%この下は\begin{document}以降

\begin{fusenmm}{My Title}
\begin{enumerate}[(1)]
\item A,A,B,C,Dを1列に並べる並べ方は何通りあるか。
\item A,A,B,B,C,Dを1列に並べる並べ方は何通りあるか。
\end{enumerate}
\end{fusenmm}

\begin{fusenmz}{My Title}
\begin{enumerate}[(1)]
\item A,A,B,C,Dを1列に並べる並べ方は何通りあるか。
\item A,A,B,B,C,Dを1列に並べる並べ方は何通りあるか。
\end{enumerate}
\end{fusenmz}

f:id:nix_campane:20210110144154j:plain

前回紹介したリングノート枠の中で使えば、付箋ノート風になってますます可愛いのでは…?

なお、付箋らしさは損なわれるが、一応ページまたぎも可能である。