GruntでSASS/SCSSをビルドする方法について解説します。
パッケージのインストール
まずはNodeプロジェクトを作成します。
$ npm init -y
必要なパッケージをインストールしていきます。
$ npm install -D grunt grunt-sass node-sass grunt-postcss autoprefixer@^9 grunt-contrib-watch load-grunt-tasks
インストールするパッケージは以下のとおりです。実際に使用したバージョンも併記しておきます。
- grunt 1.5.3
- grunt-sass 3.1.0
- node-sass 7.0.1
- grunt-postcss 0.9.0
- autoprefixer 9.8.8
- grunt-contrib-watch 1.1.0
- load-grunt-tasks 5.1.0
また、Node.jsのバージョンは16.14.2
、npmのバージョンは8.10.0
を使用しています。
執筆時点(2022/05/17)では、autoprefixer
はバージョン指定なしでインストールするとv10
系がインストールされます。grunt-postcss
v0.9
系と組み合わせると、Warning: [object Object] is not a PostCSS plugin Use --force to continue.
という警告が発生して実行に失敗(Aborted)します。そのため、バージョン指定なしで上記エラーが発生する場合は、npm install -D autoprefixer@^9
のようにv9
系を指定してインストールしてください。
grunt-sass
GruntでSASS/SCSSをビルドするパッケージにはgrunt-sass
とgrunt-contrib-sass
がありますが、grunt-contrib-sass
の方はRubyのsass
を使用しています。
実際にインストールするとわかりますが、インストール時に以下のメッセージが出力され、Rubyのsass
は非推奨に なっていることがわかります。
Ruby Sass has reached end-of-life and should no longer be used.
このため、grunt-contrib-sass
ではなく、node-sass
が使用できるgrunt-sass
を使用しています。
grunt-postcss、autoprefixer
ベンダープリフィックスを自動で付与するために使用します。
grunt-contrib-watch
SASS/SCSSを開発環境でビルドするときは都度コマンドを打ってビルドするのではなく、自動でビルドする方が楽だと思いますので、変更監視用のgrunt-contrib-watch
を使用します。
load-grunt-tasks
インストールしたgrunt-*
パッケージを使用するためには、Gruntfile.js内
で
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-sass');
のようにロードする必要があります。少ないうちは特に問題になりませんが、ロードするパッケージが多くなると管理が煩雑になるため、以下のように書くだけでロードできるload-grunt-tasks
を使用しています。
require("load-grunt-tasks")(grunt);
SASS/SCSSをビルドする
ではGruntfile.js
を作成していきます。
本例では、以下のような構造のプロジェクトになっており、sass/main.scss
をビルドしてdist/css/main.css
として出力するGruntfile.js
を作成しています。
.
├── dist/
│ └── css/
│ └── main.css
├── sass/
│ └── main.scss
├── Gruntfile.js
├── node_modules/
├── package-lock.json
└── package.json
動作確認のために用意したsass/main.scss
は以下のようになっています。
.button {
border: 1px;
background-image: linear-gradient(to bottom, #8bcc8e 0%, #a7f5ab 100%);
&:hover {
border: 2px;
}
}
これをビルドするGruntfile.js
は以下のとおりです。
const sass = require("node-sass");
module.exports = function (grunt) {
grunt.initConfig({
// Sassタスク
sass: {
options: {
implementation: sass,
style: "expanded",
},
dist: {
files: {
"dist/css/main.css": "sass/main.scss",
},
},
},
});
require("load-grunt-tasks")(grunt);
grunt.registerTask("build", ["sass"]);
};
sassタスク
sass
タスクでは実装(implementation
)にnode-sass
を指定しています。その他のオプションは自由ですが、ビルドされたCSSファイルを確認したかったので、style: "expanded"
を指定しています。
タスクの定義(build)
本例では、build
タスクを定義しています。
package.json
にbuild
タスクを実行するスクリプトを作成し、
{
・・・
"scripts": {
"build": "grunt build",
・・・
},
}
実行してみましょう。
$ npm run build
> example@1.0.0 build
> grunt build
Running "sass:dist" (sass) task
Done.
エラーなく実行され、dist/css/main.css
に以下の内容が出力されました。
.button {
border: 1px;
background-image: linear-gradient(to bottom, #8bcc8e 0%, #a7f5ab 100%); }
.button:hover {
border: 2px; }
Autoprefixerを使用する
次にベンダープリフィックスが自動付与されるようにGruntfile.js
を修正します。
const sass = require("node-sass");
const autoprefixer = require("autoprefixer"); // 追加
module.exports = function (grunt) {
grunt.initConfig({
// Sass
sass: {
options: {
implementation: sass,
style: "expanded",
},
dist: {
files: {
"dist/css/main.css": "sass/main.scss",
},
},
},
// <- ここから
// PostCSS
postcss: {
options: {
processors: [autoprefixer()],
},
dist: {
src: "dist/css/main.css",
},
},
// ここまでを追加 ->
});
require("load-grunt-tasks")(grunt);
grunt.registerTask("build", ["sass", "postcss"]); // <- "postcss"を追加
};
sass
タスクで出力されたdist/css/main.css
に対してベンダープリフィックスを付与するようにしています。SASS/SCSSファイルではなくCSSファイルに対して実行する点に注意してください。
次にAutoprefixerがCSSにどのベンダープリフィックスをつけるかなど決めるために使用する.browserslistrcを
作成します。
last 1 versions
ie >= 11
設定値自体はベンダープリフィックスがつくのを確認するために設定しているものですので、推奨設定とかそういうものではありません。
こちらも同様に実行してみます。
$ npm run build
> example@1.0.0 build
> grunt build
Running "sass:dist" (sass) task
Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.
Done.
sass
タスクの後にpostcss
タスクが実行されていることがわかります。
出力されたdist/css/main.css
を見てみると、linear-gradient
にベンダープリフィックスがついた行が出力されていることがわかります。
.button {
border: 1px;
background-image: -webkit-linear-gradient(top, #8bcc8e 0%, #a7f5ab 100%);
background-image: linear-gradient(to bottom, #8bcc8e 0%, #a7f5ab 100%); }
.button:hover {
border: 2px; }
Autoprefixerを書き方について注意事項
Autoprefixerの使用方法を調べると以下のような書き方をしているサイトもあります。
postcss: {
options: {
processors: [
autoprefixer({
browsers: ["last 1 versions", "ie >= 11"],
}),
],
},
dist: {
src: "dist/css/prime.css",
},
},
本記事の執筆時点(2022/05/17)では、この書き方をして実行してみると以下のようなメッセージが出力されます。
$ npm run build
> primecss@1.0.0 build
> grunt build
Replace Autoprefixer browsers option to Browserslist config.
Use browserslist key in package.json or .browserslistrc file.
Using browsers option can cause errors. Browserslist config
can be used for Babel, Autoprefixer, postcss-normalize and other tools.
If you really need to use option, rename it to overrideBrowserslist.
Learn more at:
https://github.com/browserslist/browserslist#readme
Tweets by Browserslist
Running "sass:dist" (sass) task
Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.
Done.
この例では正しく動作しているものの、説明では、
browsers
オプションではなくpackage.json
または.browserslistrc
を使用することbrowsers
オプションを使うとエラーが発生することがある- どうしても使いたい場合は
overrideBrowserslist
オプションを使用すること
となっています。毎回赤い文字でメッセージが表示されるのも困りますので、本記事では.browserslistrc
を使用しています。
SASS/SCSSファイルを監視する
最後にファイルの変更を監視するように変更し、都度ビルドコマンドを実行しなくても済むようにしましょう。
const sass = require("node-sass");
const autoprefixer = require("autoprefixer");
module.exports = function (grunt) {
grunt.initConfig({
// <- ここから
// Watch
watch: {
target: {
files: ["sass/**/*"],
tasks: ["sass", "postcss"],
},
},
// ここまでを追加 ->
// Sass
sass: {
options: {
implementation: sass,
style: "expanded",
},
dist: {
files: {
"dist/css/main.css": "sass/main.scss",
},
},
},
// PostCSS
postcss: {
options: {
processors: [autoprefixer()],
},
dist: {
src: "dist/css/main.css",
},
},
});
require("load-grunt-tasks")(grunt);
grunt.registerTask("build", ["sass", "postcss"]);
grunt.registerTask("build:watch", ["sass", "postcss", "watch"]); // <- build:watchタスクを追加
};
タスクの実行時に一度SASS/SCSSをビルドし、以降は変更されるたびにSASS/SCSSをビルドしたいので、["sass", "postcss", "watch"]
のように指定しています。
最初の"sass", "postcss"
がないと、何かしら変更を加えないと初回のビルドが行われないのでご注意ください。
本記事では、監視を行うタスクはwatch
タスクとし、実行するために定義するタスクをbuild:watch
タスクとしています。仮に、grunt.registerTask("watch", ["sass", "postcss", "watch"]);
のようにしてしまうと、["sass", "postcss", "watch"]
の"watch"
が自分自身を呼び出してしますため、無限ループに陥ってしまいます。initConfig
で定義しているタスクもregisterTask
で定義しているタスクも同じタスクですので、タスク名の重複にはご注意ください。
package.json
にwatch
スクリプトを追加し、作成したbuild:watch
タスクを呼び出すように修正します。
{
・・・
"scripts": {
"build": "grunt build",
"watch": "grunt build:watch",
・・・
},
}
では、実行してみます。
$ npm run watch
> primecss@1.0.0 watch
> grunt build:watch
Running "sass:dist" (sass) task
Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.
Running "watch" task
Waiting...
実行後、sass
タスク、postcss
タスクの順に実行し、最後にwatchタスクを実行して監視状態になったことがわかります。
では、監視しているsass/main.scssを
更新してみましょう。使用しているエディタによって異なりますが、ファイル自体変更しなくても保存するだけでタイムスタンプが変わるので、変更を検知してくれます。
>> File "sass/main.scss" changed.
Running "sass:dist" (sass) task
Running "postcss:dist" (postcss) task
>> 1 processed stylesheet created.
Running "watch" task
Completed in 0.017s at Sat May 21 2022 23:27:13 GMT+0900 (日本標準時) - Waiting...
監視対象の指定について
sass/main.scss
をビルド対象としているため、sass/**/*
を監視対象としています。sass/*
ではなくsass/**/*
を監視対象としているのは、今後サブディレクトリを作成した場合でも、きちんと変更が検知されるようにするためです。