【Gulp】sassの@importを@useに切り替えついでにpugからejsに変えてみた。(コーディング環境構築)

sassの@importが2022年10月1日までに廃止される予定なので、重〜い腰を上げて@useに切り替える作業をした。
タスクランナーのGulpで、@importのときとほぼ同じ仕様で@useが使えるようにしてみたつもり。
あと、今までpugでコーディングしてたけど、サーバーで公開済のHTMLを修正するときにインデントの調整に時間取られたりめんどくさくなってきた。
それだったらpugからejsにして、head・header・各ページ・footerのパーツにわけて効率化してしまったほうが良いのでは?てことで、ついでにpugをejsに変更してみた。

元のGulpの状態は「タスクランナーGulp4で環境構築してsassとpugでコーディングを楽に!」に記載してある。

ディレクトリ構造

ディレクトリ構造はこんな感じ。

test
├── dist
│   ├── assets
│   │   ├── css
│   │   │   ├── main.css
│   │   │   ├── main.css.map
│   │   │   ├── main.css.min.map
│   │   │   └── main.min.css
│   │   └── js
│   │       └── main.min.js
│   ├── index.html
│   └── test.html
├── gulpfile.js
│   ├── index.js
│   └── modules.js
├── package.json
└── src
    ├── ejs
    │   ├── _inc
    │   │   ├── _footer.ejs
    │   │   ├── _head.ejs
    │   │   └── _header.ejs
    │   ├── index.ejs
    │   └── test.ejs
    ├── js
    │   ├── accordion.js
    │   ├── modal.js
    │   ├── scrollAnimation.js
    │   └── scrollup.js
    └── scss
        ├── base
        │   ├── _base.scss
        │   ├── _common.scss
        │   ├── _heading.scss
        │   └── _reset.scss
        ├── components
        │   ├── _accordion.scss
        │   ├── _animation.scss
        │   ├── _breadcrumb.scss
        │   ├── _btn.scss
        │   ├── _footer.scss
        │   ├── _form.scss
        │   ├── _grid.scss
        │   ├── _header.scss
        │   ├── _page.scss
        │   ├── _post.scss
        │   ├── _scrollAnimation.scss
        │   └── _totop.scss
        └── main.scss

以前のsassフォルダの中はmain.scssとcompornentsフォルダで、パーツはすべてcompornentsフォルダにまとめて入れていた。
今回は@useにするためbaseフォルダを作り、カラー・mixinなど、使い回すであろうパーツとreset.scssをまとめた。
制作内容によってcompornentsの使うパーツのみ残し、あとは削除する仕様。

gulpfile.js/modules.jsの書き換え

sassをdart sassに、pugをejsに変更。

//ビフォー
  pug: require('gulp-pug'),
  sass: require('gulp-sass'),
  minifyCSS: require('gulp-csso'),
  concat: require('gulp-concat'),
  browserSync: require('browser-sync'),
  plumber: require('gulp-plumber'),
  notify: require('gulp-notify'),
  autoprefixer: require('gulp-autoprefixer'),
  sourcemaps: require('gulp-sourcemaps'),
  rename: require('gulp-rename'),
  imagemin: require('gulp-imagemin'),
  changed: require('gulp-changed'),
  uglifyes: require('uglify-es'),
  composer: require('gulp-uglify/composer'),
};

//アフター
module.exports = {
  ejs: require("gulp-ejs"),
  sass:require('gulp-dart-sass'),
  sassGlob : require('gulp-sass-glob-use-forward'),
  minifyCSS: require('gulp-csso'),
  concat: require('gulp-concat'),
  browserSync: require('browser-sync'),
  plumber: require('gulp-plumber'),
  notify: require('gulp-notify'),
  autoprefixer: require('gulp-autoprefixer'),
  sourcemaps: require('gulp-sourcemaps'),
  rename: require('gulp-rename'),
  imagemin: require('gulp-imagemin'),
  changed: require('gulp-changed'),
  uglifyes: require('uglify-es'),
  composer: require('gulp-uglify/composer'),
};

gulpfile.js/index.jsの書き換え(アフターのみ)

const { src, dest, parallel, watch } = require('gulp');
const $ = require('./modules.js');
const uglify = $.composer($.uglifyes, $.composer);

const path = {
  src: './src',
  dist: './dist',
  distAssets: './dist/assets',
};

function html() {
  return src([`${path.src}/ejs/*.ejs`, `!${path.src}/ejs/**/_*.ejs`])
    .pipe(
        $.plumber({
          errorHandler: $.notify.onError('Error: <%= error.message %>'),
        })
      )
    .pipe($.ejs())
    .pipe($.rename({ extname: ".html" }))
    .pipe(dest(path.dist))
    .pipe(
      $.browserSync.reload({
        stream: true,
        once: true,
      })
    );
}

function css() {
  return src(`${path.src}/scss/*.scss`)
    .pipe($.sourcemaps.init())
    .pipe($.sass.sync({outputStyle: 'expanded'}))
    .on('error', $.sass.logError)
    .pipe($.sassGlob())
    .pipe($.autoprefixer())
    .pipe($.sourcemaps.write(`/`))
    .pipe(dest(`${path.distAssets}/css`))
    .pipe(
      $.rename({
        suffix: '.min',
      })
    )
    .pipe($.minifyCSS())
    .pipe(dest(`${path.distAssets}/css`))
    .pipe(
      $.browserSync.reload({
        stream: true,
        once: true,
      })
    );
}

function js() {
  return src(`${path.src}/js/**/*.js`, { sourcemaps: true })
    .pipe(
      $.plumber({
        errorHandler: $.notify.onError('Error: <%= error.message %>'),
      })
    )
    .pipe(uglify({ output: { comments: /^!/ } }))
    .pipe(
      $.concat('main.min.js', {
        newLine: '\n',
      })
    )
    .pipe(dest(`${path.distAssets}/js`, { sourcemaps: true }))
    .pipe(
      $.browserSync.reload({
        stream: true,
        once: true,
      })
    );
}

function images() {
  return src(`${path.src}/images/**/**`)
    .pipe($.changed(`${path.distAssets}/images/`))
    .pipe(
      $.imagemin({
        optimizationLevel: 3,
      })
    )
    .pipe(dest(`${path.distAssets}/images/`));
}

function bs() {
  $.browserSync.init({
    port: 3030, //案件ごとに番号変えてもいいかも
    server: {
      baseDir: path.dist,
      index: 'index.html'
    },
    open: 'external',// IPで開く
  });
}

exports.html = html;
exports.css = css;
exports.js = js;
exports.bs = bs;
exports.images = images;

exports.default = parallel([html, css, js, images, bs], () => {
  watch(`${path.src}/ejs/**`, html);
  watch(`${path.src}/scss/**`, css);
  watch(`${path.src}/js/**`, js);
  watch(`${path.src}/images/**`, images);
});

gulpfile.js/index.jsのpugからejsに書き換え部分

// ビフォー
function html() {
  return src([`${path.src}/pug/*.pug`, `!${path.src}/pug/**/_*.pug`])
    .pipe(
      $.plumber({
        errorHandler: $.notify.onError('Error: <%= error.message %>'),
      })
    )
    .pipe(
      $.pug({
        pretty: true,
      })
    )
    .pipe(dest(path.dist))
    .pipe(
      $.browserSync.reload({
        stream: true,
        once: true,
      })
    );
}

// アフター
function html() {
  return src([`${path.src}/ejs/*.ejs`, `!${path.src}/ejs/**/_*.ejs`])
    .pipe(
        $.plumber({
          errorHandler: $.notify.onError('Error: <%= error.message %>'),
        })
      )
    .pipe($.ejs())
    .pipe($.rename({ extname: ".html" }))
    .pipe(dest(path.dist))
    .pipe(
      $.browserSync.reload({
        stream: true,
        once: true,
      })
    );
}


// watchの部分書き換え
// ビフォー
watch(`${path.src}/pug/**`, html);
// アフター
watch(`${path.src}/ejs/**`, html);

gulpfile.js/index.jsのsass書き換え部分

SassからDartSass仕様に書き換え。
書き換えたとき、CSSはSCSSからの生成時、圧縮データだけ生成する仕様にしたんだけど、やっぱりSassのときと同じ普通のcssと圧縮したcss.minファイルが生成される仕様に。

たまに案件によっては圧縮せず書き換えしやすいCSSの状態でデータを渡すことがあるんよね〜。
両方生成しとけば臨機応変に対応できる!

// ビフォー
function css() {
  return src(`${path.src}/scss/*.scss`)
    .pipe(
      $.plumber({
        errorHandler: $.notify.onError('Error: <%= error.message %>'),
      })
    )
    .pipe($.sourcemaps.init())
    .pipe($.sass())
    .pipe($.autoprefixer())
    .pipe($.sourcemaps.write())
    .pipe(dest(`${path.distAssets}/css`))
    .pipe(
      $.rename({
        suffix: '.min',
      })
    )
    .pipe($.minifyCSS())
    .pipe(dest(`${path.distAssets}/css`))
    .pipe(
      $.browserSync.reload({
        stream: true,
        once: true,
      })
    );
}

// アフター
function css() {
  return src(`${path.src}/scss/*.scss`)
    .pipe($.sourcemaps.init())
    .pipe($.sass.sync({outputStyle: 'expanded'}))
    .on('error', $.sass.logError)
    .pipe($.sassGlob())
    .pipe($.autoprefixer())
    .pipe($.sourcemaps.write(`/`))
    .pipe(dest(`${path.distAssets}/css`))
    .pipe(
      $.rename({
        suffix: '.min',
      })
    )
    .pipe($.minifyCSS())
    .pipe(dest(`${path.distAssets}/css`))
    .pipe(
      $.browserSync.reload({
        stream: true,
        once: true,
      })
    );
}

package.jsonの書き換え

// ビフォー
{
  "name": "basebox",
  "version": "1.0.0",
  "description": "basebox website",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "gulp"
  },
  "author": "yukipan",
  "license": "ISC",
  "devDependencies": {
    "browser-sync": "^2.26.14",
    "gulp": "^4.0.2",
    "gulp-autoprefixer": "^7.0.1",
    "gulp-changed": "^4.0.2",
    "gulp-concat": "^2.6.1",
    "gulp-csso": "^4.0.1",
    "gulp-imagemin": "^7.1.0",
    "gulp-notify": "^3.2.0",
    "gulp-plumber": "^1.2.1",
    "gulp-pug": "^4.0.1",
    "gulp-rename": "^2.0.0",
    "gulp-sass": "^4.1.0",
    "gulp-sourcemaps": "^3.0.0",
    "gulp-uglify": "^3.0.2",
    "uglify-es": "^3.3.9",
    "webpack": "^5.24.0",
    "webpack-stream": "^6.1.2"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ]
}


// アフター
{
  "name": "basebox",
  "version": "1.0.0",
  "description": "basebox website",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "start": "gulp"
  },
  "author": "yukipan",
  "license": "ISC",
  "devDependencies": {
    "browser-sync": "^2.27.5",
    "gulp": "^4.0.2",
    "gulp-dart-sass": "^1.0.2",
    "gulp-sass-glob-use-forward": "^0.1.3",
    "gulp-autoprefixer": "^7.0.1",
    "gulp-changed": "^4.0.2",
    "gulp-concat": "^2.6.1",
    "gulp-csso": "^4.0.1",
    "gulp-imagemin": "^7.1.0",
    "gulp-notify": "^4.0.0",
    "gulp-plumber": "^1.2.1",
    "gulp-ejs": "^5.1.0",
    "gulp-rename": "^2.0.0",
    "gulp-sourcemaps": "^3.0.0",
    "gulp-uglify": "^3.0.2",
    "uglify-es": "^3.3.9",
    "webpack": "^5.24.0",
    "webpack-stream": "^6.1.2"
  },
  "browserslist": [
    "last 2 versions",
    "ie >= 11",
    "Android >= 4"
  ]
}

src/scss/main.scssを@importから@useに書き換え

@importのときのほうが細分化してたな〜。

@charset "UTF-8";

// ビフォー
@import
  "components/base/reset",
  "components/base/base",
  // parts
  "components/parts/common",
  "components/parts/header",
  "components/parts/footer",
 // page
  "components/page/page";


// アフター
@use "base/reset";
@use "base/base";
@use "base/common";
@use "base/heading";

@use "components/header";
@use "components/footer";
@use "components/page";
 ・
 ・
 ・
※componentsフォルダに置いてある使うscssのファイル名を全部記載

src/scss/各ファイルに使い回す別のscssファイルを引っ張ってくる記述

@useになって、使い回すときはそのファイル名を記述しないといけなくなった。
例えば、_common.scssで_base.scssに記述してあるmixinを使いたいときは、「baseに記述してあるコードを引っ張ってきますよ〜」っていう記述が必要。
この記述がないと@include〜って記述しても「そんなもん無いですよ〜」ってエラーが出てしまう。
各ファイルの一番初めに記述しておけばOK。

@use '../base/base' as *;

_base.scssはほぼ使い回すから全ファイルの先頭に記述しておいて、_heading.scssなど他のファイルを使い回すときは都度追加することにした。

gulp-sass-glob-use-forwardを入れると手間が省ける!

DartSassは、「@use ‘../base/base’ as *;」ではなく、「@use ‘../base/base’ as b;」のように記述して、beseに記述したものを使うときはasのあとに「*」ではなく名前をつけて、使うときは名前をつけないといけなかった。毎回書くのめんどくさいよね〜。
ってことで、「gulp-sass-glob-use-forward」というプラグインをGulpに入れて昔のSassと同じ記述ができるようにした。

これで昔書いたコードも書き換えることなく使い回せるし、効率化アップ!

//_base.scss(引用ファイル)
$c-gray : #ccc;

---------------

※ gulp-sass-glob-use-forward入れる前

//_page.scss
@use '../base/base' as b; ←引っ張ってくる名前「b」

.hoge{
 border: 1px solid b.$c-gray; ←いちいち「b.」付けるのめんどくさい
}


※ gulp-sass-glob-use-forward入れた後

//_page.scss
@use '../base/base' as *;

.hoge{
 border: 1px solid $c-gray; ←「b.」とか付けずに昔のまま使える!
}

DartSassとejsに換えた開発環境パック

長々と書いたけど、ダウンロードしてすぐ使えるパックがあったら便利だよね。
SCSSの中身はひとそれぞれの記述の方法があると思うから、必要最低限の開発環境パック(gulpfile.js・package.json・srcフォルダ)を作ってみたのでダウンロードして各自お好きにカスタムして使ってください。
ついでに記事の紹介してもらえると嬉しいです。

ダウンロード:gulppack2022.zip

ダウンロード後、環境つくりたいところ(macだと書類とか?)に解凍したデータをフォルダごと持っていって、黒い画面でフォルダのディレクトリに設定。
「npm install」でプログラムが走る。
終わったら「gulp」でブラウザが開く。
※node.jsがインストールされていることが前提

こんな画面が立ち上がったら成功。
もっと良い書き方とかカスタムの仕方があると思うので、あとはコーディングなりカスタムなりお好きにどうぞ!

参考にさせてもらったサイト

「dart @use」や、「dart forward」というワードで検索かけていろいろなサイトを見たから他のサイトの情報も参考にさせてもらったと思う。。けど、どれを見たか探しきれなかった、、、参考にさせていただいたサイトさんありがとうございます!
主に参考にさせてもらったサイトはリンクを控えていたので貼り付け。

Dart Sass × FLOCSS コーディング用のgulpキットを作成しました

DartSassがなかなか辛かったのでGulpを修正してみた

大変参考になりました!ありがとうございます。

ABOUT US
yukipan
Web制作会社で働いてます。パンダとかリラックマとか、まあるいものが好き。好奇心旺盛で、何にでも興味をもってしまう。とりあえずやってみてから取捨選択するのがモットー。今はグリーンカレーとチャイと株式投資がブーム。