npm scriptsでSassをコンパイルする(Dart Sassと共通管理、StyleLint、PostCSS)
要件
- srcディレクトリにあるSassファイルを対象にコンパイルしてhtdocsディレクトリに出力する
- PostCSSをhtdocsディレクトリ内のCSSファイルに適用し、cssnanoによる最適化はproductionビルドのみで実行する
- Dart Sassを使用し、変数や関数を共通化して
@use
で使えるようにする - Sassファイルを保存するたびにStylelint(自動修正付き)を実行する
パッケージをインストールする
CSS関連の必要なパッケージをインストールします。
npm i -D autoprefixer cssnano postcss postcss-cli prettier sass stylelint stylelint-config-standard-scss stylelint-prettier stylelint-scss
リセットCSSとメディアクエリを管理するライブラリをインストールします(任意)。
npm i normalize.css sass-mq
クロスプラットフォームに対応して簡潔に記述できるnpm-run-allとファイルの監視機能があるonchangeもインストールします。
npm i -D npm-run-all onchange
ディレクトリ構造
以下のディレクトリ構造で構成しています。
.
├── postcss.config.js
└── src
└── assets
└── css
├── components
│ ├── _Button.scss
│ ├── _LinkText.scss
│ └── _index.scss
├── global
│ ├── _base.scss
│ ├── _index.scss
│ ├── function
│ │ ├── _index.scss
│ │ ├── _rem.scss
│ │ └── _strip-unit.scss
│ ├── mixin
│ │ ├── _hack.scss
│ │ ├── _index.scss
│ │ └── _sr-only.scss
│ └── variable
│ ├── _easing.scss
│ ├── _global.scss
│ ├── _index.scss
│ └── _mq.scss
├── namespace
│ └── common
│ ├── _Br.scss
│ ├── _Button.scss
│ ├── _LinkText.scss
│ ├── _SrOnly.scss
│ └── _index.scss
└── site.scss
-
global
-
function
:サイト共通のfunction -
variable
:サイト共通の変数 -
mixin
:サイト共通のmixin -
_base.scss
:サイト共通のデフォルトスタイル
-
-
components
:mixin化したコンポーネントのスタイル -
namespace
:サイト共通やカテゴリごとのスタイル
Dart Sassを設定する
site.scss
site.scss
には変数や関数を除いた、実際に出力する記述を@use
で読み込みます。
@charset "UTF-8";
@use "../../../node_modules/normalize.css/normalize";
@use "global/_base";
@use "namespace/common";
namespace/common
namespace/common/_index.scss
は以下のようにサイト共通のスタイルを@forward
します。
@forward "_Br";
@forward "_Button";
@forward "_Delimiter";
@forward "_LinkText";
@forward "_SrOnly";
たとえば_Delimiter.scss
は以下のように.common-
からクラス名を付けます。
.common-Delimiter {
display: inline-block;
}
プロダクトページであればnamespace/product/
に_List.scss
などを作り、.product-List
のようなクラス名を付けていきます。
global
global/_index.scss
は以下のように変数と関数、ライブラリを読み込んでいます。
@forward "function";
@forward "variable";
@forward "mixin";
@import "../../../../node_modules/sass-mq/mq";
function
・variable
・mixin
ともに_index.scss
で@forward
で各ファイルをインポートしています。
@forward "_rem";
@forward "_strip-unit";
@forward "_global";
@forward "_easing";
@forward "_mq";
@forward "_hack";
@forward "_sr-only";
../../../../node_modules/sass-mq/mq
は「sass-mq」をnode_modulesから直接インポートしています。
_mq.scss
は以下のようにしています。
$mq-breakpoints: (
sm: 375px,
md: 768px,
lg: 1024px,
xl: 1440px,
);
@import "../../../../../node_modules/sass-mq/_mq";
components
components/_index.scss
は以下のようにコンポーネント用のスタイルを読み込んでいます。
@forward "_Button";
@forward "_LinkText";
たとえばcomponents/_Button.scss
で以下のようにデフォルトスタイルを作成しておきます。
@use "../global" as g;
@mixin Button() {
display: inline-flex;
align-items: center;
justify-content: center;
position: relative;
max-width: 100%;
margin: 0;
padding: g.rem(15) g.rem(44) g.rem(14);
text-align: center;
text-decoration: none;
font-family: inherit;
font-size: g.rem(15);
line-height: g.div(21, 15);
border: 1px solid transparent;
border-radius: g.rem(999);
background: transparent;
color: inherit;
cursor: pointer;
transition-timing-function: g.$ease;
transition-duration: g.$transition-duration;
appearance: none;
&[type="button"],
&[type="reset"],
&[type="submit"] {
appearance: none;
}
}
globalとcomponentsを@useで使用する
namespace/common/_Button.scss
で使用する例です。
-
@use
でglobal
をg
として、components
をc
として参照する -
@include c.Button;
としてボタンコンポーネントをインクルードする -
padding-top: g.rem(14);
のようにサイト共通のfunctionでpxからremに変換する
@use "../../global" as g;
@use "../../components" as c;
.common-Button {
@include c.Button;
}
.common-Button.-full {
width: 100%;
max-width: none;
}
.common-Button.-auto {
width: auto;
min-width: auto;
}
.common-Button.-large {
min-height: g.rem(70);
padding-top: g.rem(14);
padding-bottom: g.rem(14);
font-size: g.rem(17);
border-width: 2px;
}
.common-Button.-small {
padding: g.rem(12) g.rem(28) g.rem(11);
font-size: g.rem(13);
}
Dart Sassの設定は以上です。
Stylelintを設定する
.stylelintrc
を作成します。
touch .stylelintrc
以下のように最小構成を設定しています。
{
"extends": [
"stylelint-config-standard-scss",
"stylelint-prettier/recommended"
],
"syntax": "scss",
"plugins": [
"stylelint-scss",
"stylelint-prettier"
],
"rules": {
"prettier/prettier": [
true,
{
"printWidth": 100,
"tabWidth": 2,
"useTabs": false,
"singleQuote": false,
"trailingComma": "all",
"bracketSpacing": false
}
],
"selector-class-pattern": null,
"scss/selector-no-union-class-name": true,
"scss/at-mixin-pattern": null
}
}
- Stylelintのv14からscss用の拡張を加えたコンフィグファイルが必要になっているので、「stylelint-config-standard-scss」を使用しています(
.stylelintrc
に設定を追加するだけでもSassが使えるようになりますが、コンフィグファイルのほうがわかりやすいので採用しました) - Stylelintのv15からフォーマットに関するルールが非推奨になっているので、Deprecated一覧に記載されている設定を外しています
- ルールは次の通りです
-
selector-class-pattern:ケバブケース以外のクラス名がエラーになってしまうので、
null
で制限をかけないようにしています(正規表現が使えるのでプロジェクトによっては詳細に設定してもいいかもしれません) -
scss/selector-no-union-class-name:
&_Element
のように新しいクラス名を生成できてしまうのをtrue
で禁止しています -
scss/at-mixin-pattern:ケバブケース以外のmixin名がエラーになってしまうので、
null
で制限をかけないようにしています(正規表現が使えるのでプロジェクトによっては詳細に設定してもいいかもしれません)
-
selector-class-pattern:ケバブケース以外のクラス名がエラーになってしまうので、
PostCSSを設定する
postcss.config.js
を作成します。
touch postcss.config.js
以下のように最小構成を設定しています。
module.exports = (ctx) => {
return {
plugins: {
autoprefixer: {},
cssnano: ctx.env === "production" ? {} : false,
},
};
};
-
autoprefixer
:初期値で実行します -
cssnano
:npm scriptsでNODE_ENV=production
を渡した場合は実行、development
などのそれ以外を渡した場合は実行しないようにします
npm scriptsを設定する
CSSに関連する処理だけを抜き出しています。
"start": "run-s -c dev watch",
"build": "npm-run-all -s clean -p build:*",
"watch": "run-p watch:*",
"watch:css": "onchange \"src/**/*.scss\" -- npm run dev:css",
"dev": "run-p dev:*",
"dev:css": "NODE_ENV=development run-s -c css:*",
"build:css": "NODE_ENV=production run-s -c css:*",
"css:stylelint": "stylelint \"src/**/*.scss\" --fix",
"css:sass": "sass src/assets/css/site.scss htdocs/assets/css/site.css",
"css:postcss": "postcss htdocs/assets/css/site.css -o htdocs/assets/css/site.css",
-
dev
は開発用のビルド、build
は本番用のビルドとしています -
run-s
は順番に実行、-c
はエラーが起きても最後の処理まで止まらずに実行するオプションです -
run-s -c css:*
のようにすると、scripts
にあるcss:
から始まるスクリプトを上から順番に実行します(今回はstylelint→sass→postcssの順) -
stylelint \"src/**/*.scss\" --fix
のようにすべてのSassファイルを対象に、強制的に自動修正します -
sass src/assets/css/site.scss htdocs/assets/css/site.css
はコンパイル元ファイルと出力先を指定しています -
postcss htdocs/assets/css/site.css -o htdocs/assets/css/site.css
はコンパイル元ファイルと出力先(-o
)を指定しています -
onchange \"src/**/*.scss\" -- npm run dev:css
の部分でSassファイルの保存を監視、ファイルが上書きされたら一連の処理を開始します
Discussion