GruntでSASS/SCSSをビルドする

GruntでSASS/SCSSをビルドする

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-sassgrunt-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.jsonbuildタスクを実行するスクリプトを作成し、

{
  ・・・
  "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
  


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.jsonwatchスクリプトを追加し、作成した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/**/*を監視対象としているのは、今後サブディレクトリを作成した場合でも、きちんと変更が検知されるようにするためです。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次