tag:crieit.net,2005:https://crieit.net/tags/gulp-sass/feed 「gulp-sass」の記事 - Crieit Crieitでタグ「gulp-sass」に投稿された最近の記事 2021-07-05T20:32:23+09:00 https://crieit.net/tags/gulp-sass/feed tag:crieit.net,2005:PublicArticle/17485 2021-07-05T20:32:23+09:00 2021-07-05T20:32:23+09:00 https://crieit.net/posts/node-sass-adjust-node16-20210705 gulp-sass を Node.js v16 環境に合わせて調整する <p>Node.js の 16系 を試そうとしたら gulp-sass, node-sass 周りでエラーが発生したので対処をまとめておきます。</p> <h2 id="経緯"><a href="#%E7%B5%8C%E7%B7%AF">経緯</a></h2> <p>まず前提として</p> <ul> <li>Dart Sass で <code>/</code> を使った徐算が非推奨となった (代わりに <code>math.div</code> を使えとのこと) <ul> <li>参考: <a target="_blank" rel="nofollow noopener" href="https://labor.ewigleere.net/2021/06/07/dart-sass-warning-slash-as-division/">Dart Sass で DEPRECATION WARNING: Using / for division is deprecated and will be removed in Dart Sass 2.0.0. の警告が表示される - Ewig Leere(Lab2)</a></li> </ul></li> <li>上述現象を回避するため、 <code>sass</code> のバージョンを <code>1.32.12</code> で固定していた</li> </ul> <p>という事情があります。</p> <h2 id="現象"><a href="#%E7%8F%BE%E8%B1%A1">現象</a></h2> <p>この状態で Node.js のバージョンを 16系 に切り替えて <code>yarn</code> 。</p> <pre><code class="bash">error /home/node/app/node_modules/node-sass: Command failed. Exit code: 1 Command: node scripts/build.js Arguments: Directory: /home/node/app/node_modules/node-sass Output: Building: /usr/local/bin/node /home/node/app/node_modules/node-gyp/bin/node-gyp.js rebuild --verbose --libsass_ext= --libsass_cflags= --libsass_ldflags= --libsass_library= # 略 In file included from /home/node/.node-gyp/16.3.0/include/node/v8.h:30, from /home/node/.node-gyp/16.3.0/include/node/node.h:63, from ../../nan/nan.h:56, from ../src/binding.cpp:1: /home/node/.node-gyp/16.3.0/include/node/v8-internal.h: In function 'void v8::internal::PerformCastCheck(T*)': /home/node/.node-gyp/16.3.0/include/node/v8-internal.h:452:38: error: 'remove_cv_t' is not a member of 'std' !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data); ^~~~~~~~~<del> /home/node/.node-gyp/16.3.0/include/node/v8-internal.h:452:38: note: suggested alternative: 'remove_cv' !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data); ^</del>~~~~~~<del> remove_cv /home/node/.node-gyp/16.3.0/include/node/v8-internal.h:452:38: error: 'remove_cv_t' is not a member of 'std' /home/node/.node-gyp/16.3.0/include/node/v8-internal.h:452:38: note: suggested alternative: 'remove_cv' !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data); ^</del>~~~~~~<del> remove_cv /home/node/.node-gyp/16.3.0/include/node/v8-internal.h:452:50: error: template argument 2 is invalid !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data); ^ /home/node/.node-gyp/16.3.0/include/node/v8-internal.h:452:63: error: '::Perform' has not been declared !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data); ^</del>~~<del> /home/node/.node-gyp/16.3.0/include/node/v8-internal.h:452:63: note: suggested alternative: 'herror' !std::is_same<Data, std::remove_cv_t<T>>::value>::Perform(data); ^</del>~~<del> herror ../src/binding.cpp: In function 'Nan::NAN_METHOD_RETURN_TYPE render(Nan::NAN_METHOD_ARGS_TYPE)': ../src/binding.cpp:284:98: warning: cast between incompatible function types from 'void (*)(uv_work_t*)' {aka 'void (*)(uv_work_s*)'} to 'uv_after_work_cb' {aka 'void (*)(uv_work_s*, int)'} [-Wcast-function-type] int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback); ^</del>~~~~~~~<del> ../src/binding.cpp: In function 'Nan::NAN_METHOD_RETURN_TYPE render_file(Nan::NAN_METHOD_ARGS_TYPE)': ../src/binding.cpp:320:98: warning: cast between incompatible function types from 'void (*)(uv_work_t*)' {aka 'void (*)(uv_work_s*)'} to 'uv_after_work_cb' {aka 'void (*)(uv_work_s*, int)'} [-Wcast-function-type] int status = uv_queue_work(uv_default_loop(), &ctx_w->request, compile_it, (uv_after_work_cb)MakeCallback); ^</del>~~~~~~~<del> In file included from ../../nan/nan.h:56, from ../src/binding.cpp:1: ../src/binding.cpp: At global scope: /home/node/.node-gyp/16.3.0/include/node/node.h:806:43: warning: cast between incompatible function types from 'void (*)(Nan::ADDON_REGISTER_FUNCTION_ARGS_TYPE)' {aka 'void (*)(v8::Local<v8::Object>)'} to 'node::addon_register_func' {aka 'void (*)(v8::Local<v8::Object>, v8::Local<v8::Value>, void*)'} [-Wcast-function-type] (node::addon_register_func) (regfunc), \ ^ /home/node/.node-gyp/16.3.0/include/node/node.h:840:3: note: in expansion of macro 'NODE_MODULE_X' NODE_MODULE_X(modname, regfunc, NULL, 0) // NOLINT (readability/null_usage) ^</del>~~~~~~~~<del> ../src/binding.cpp:358:1: note: in expansion of macro 'NODE_MODULE' NODE_MODULE(binding, RegisterModule); ^</del>~~~~~~~~ make: *** [binding.target.mk:133: Release/obj.target/binding/src/binding.o] Error 1 make: Leaving directory '/home/node/app/node_modules/node-sass/build' gyp ERR! build error gyp ERR! stack Error: `make` failed with exit code: 2 gyp ERR! stack at ChildProcess.onExit (/home/node/app/node_modules/node-gyp/lib/build.js:262:23) gyp ERR! stack at ChildProcess.emit (node:events:394:28) gyp ERR! stack at Process.ChildProcess._handle.onexit (node:internal/child_process:290:12) gyp ERR! System Linux 5.10.25-linuxkit gyp ERR! command "/usr/local/bin/node" "/home/node/app/node_modules/node-gyp/bin/node-gyp.js" "rebuild" "--verbose" "--libsass_ext=" "--libsass_cflags=" "--libsass_ldflags=" "--libsass_library=" gyp ERR! cwd /home/node/app/node_modules/node-sass gyp ERR! node -v v16.3.0 </code></pre> <p>……滅茶苦茶怒られました (Docker内のLinux環境)。</p> <p>ちなみに Windows環境だと <code>yarn</code> 時にはエラーにはなりませんが、 Gulpタスク を走らせた際に同様のエラーメッセージが表示されます。</p> <p><a href="https://crieit.now.sh/upload_images/68677d73f1123631b69e1a1fa1061c7b60e2edbdef2fa.jpg" target="_blank" rel="nofollow noopener"><img src="https://crieit.now.sh/upload_images/68677d73f1123631b69e1a1fa1061c7b60e2edbdef2fa.jpg?mw=700" alt="Windows環境でのエラーメッセージ" /></a></p> <h2 id="対処1 (sass, gulp-sass のバージョンを上げる)"><a href="#%E5%AF%BE%E5%87%A61+%28sass%2C+gulp-sass+%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E3%82%92%E4%B8%8A%E3%81%92%E3%82%8B%29">対処1 (sass, gulp-sass のバージョンを上げる)</a></h2> <p>そこでまずは <code>sass</code> のバージョンを上げます。</p> <p>ちなみに、 <code>1.35.0</code>以降 では <code>quietDeps: true</code> のフラグを追加することで、冒頭の警告を非表示にできるようになったとのことなので、そもそもの問題は回避できるはずです。</p> <pre><code class="json"> "devDependencies": { // 略 "gulp-sass": "^4.1.0", "sass": "1.35.1", // 1.32.12 からアップデート "fibers": "^5.0.0", "gulp-autoprefixer": "^7.0.1", // 略 } </code></pre> <p>これで <code>yarn</code> してみましたが、ダメ。</p> <p>ふと <code>gulp-sass</code> を見てみると、いつの間にか <code>5.0.0</code> がリリースされているではありませんか。</p> <pre><code class="json"> "devDependencies": { // 略 "gulp-sass": "^5.0.0", // 4.1.0 からアップデート "sass": "1.35.1", // 1.32.12 からアップデート "fibers": "^5.0.0", "gulp-autoprefixer": "^7.0.1", // 略 } </code></pre> <p>そこで、 <code>gulp-sass</code> も上げます。これで <code>yarn</code> すると正常に完了。</p> <p>安心して Gulpタスク を走らせると……</p> <pre><code class="bash">../src/coroutine.cc:134: void* find_thread_id_key(void*): Assertion `thread_id_key != 0x7777' failed. </code></pre> <p>…別のエラーで怒られました。</p> <h2 id="対処2 (fibers を削除)"><a href="#%E5%AF%BE%E5%87%A62+%28fibers+%E3%82%92%E5%89%8A%E9%99%A4%29">対処2 (fibers を削除)</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/67330252/thread-id-key-0x7777-function-find-thread-id-key-file-src-coroutine-cc">node.js - (thread_id_key != 0x7777), function find_thread_id_key, file ../src/coroutine.cc, line 134 - Stack Overflow</a></li> </ul> <p>検索すると上述のエラーは <code>fibers</code> が Node.js 16系 に対応していないために発生している模様。</p> <p>そのため、 <code>fibers</code> を削除します。</p> <pre><code class="json"> "devDependencies": { // 略 "gulp-sass": "^5.0.0", // 4.1.0 からアップデート "sass": "1.35.1", // 1.32.12 からアップデート "gulp-autoprefixer": "^7.0.1", // 略 } </code></pre> <p>併せてタスクも書き換えます。</p> <pre><code class="javascript">const sass = require('gulp-sass'); sass.compiler = require('sass'); //const Fiber = require('fibers'); // 略 .pipe(sass({ // fiber: Fiber, outputStyle: 'compressed', quietDeps: true // 警告回避のために追加 }).on('error', sass.logError)) // 略 </code></pre> <p><code>fibers</code> 関係を削除。</p> <p>これで <code>yarn</code> し直してタスクを再実行。</p> <pre><code class="bash">Error in plugin "gulp-sass" Message: gulp-sass 5 does not have a default Sass compiler; please set one yourself. Both the `sass` and `node-sass` packages are permitted. For example, in your gulpfile: var sass = require('gulp-sass')(require('sass')); </code></pre> <p>……別のエラーが発生しました。どうやら <code>gulp-sass</code> の Scssトランスパイラ の指定方法が変わったようです。</p> <h2 id="対処3 (gulp-sass のScssトランスパイラ指定方法を変更)"><a href="#%E5%AF%BE%E5%87%A63+%28gulp-sass+%E3%81%AEScss%E3%83%88%E3%83%A9%E3%83%B3%E3%82%B9%E3%83%91%E3%82%A4%E3%83%A9%E6%8C%87%E5%AE%9A%E6%96%B9%E6%B3%95%E3%82%92%E5%A4%89%E6%9B%B4%29">対処3 (gulp-sass のScssトランスパイラ指定方法を変更)</a></h2> <pre><code class="javascript">const sass = require('gulp-sass')(require('sass')); //const Fiber = require('fibers'); // 略 .pipe(sass({ // fiber: Fiber, outputStyle: 'compressed', quietDeps: true // 警告回避のために追加 }).on('error', sass.logError)) // 略 </code></pre> <p>これでようやくタスクが正常に走るようになりました。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li>Dart Sass の警告回避: <ul> <li><a target="_blank" rel="nofollow noopener" href="https://sass-lang.com/documentation/js-api#quietdeps">Sass: JavaScript API</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/twbs/bootstrap/issues/34051">Sass deprecation warning: Using `/` for division is deprecated · Issue #34051 · twbs/bootstrap · GitHub</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/sass/dart-sass/issues/1333">support quietDeps flag · Issue #1333 · sass/dart-sass · GitHub</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/sass/dart-sass/issues/672">Add a --quiet-upstream flag · Issue #672 · sass/dart-sass · GitHub</a></li> </ul></li> <li>fibers: <a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/67330252/thread-id-key-0x7777-function-find-thread-id-key-file-src-coroutine-cc">node.js - (thread_id_key != 0x7777), function find_thread_id_key, file ../src/coroutine.cc, line 134 - Stack Overflow</a></li> <li>gulp-sass: <a target="_blank" rel="nofollow noopener" href="https://www.npmjs.com/package/gulp-sass">gulp-sass - npm</a></li> </ul> arm-band tag:crieit.net,2005:PublicArticle/16652 2021-01-26T23:55:22+09:00 2021-01-26T23:55:22+09:00 https://crieit.net/posts/gulp-sass-pseudo-dynamic-import-scss-20210120 gulp-sass から Scss を疑似的な動的読み込みを行う <h2 id="経緯"><a href="#%E7%B5%8C%E7%B7%AF">経緯</a></h2> <p>Scss で <code>@import</code>, <code>@use</code>, <code>@forward</code> のような他のファイルを読み込む機能は、 @ディレクティブ 内では使用できないません。そのため、例えば以下のようなことができません。</p> <pre><code class="scss">$flag: true; @if ($flag) { @use "parts1.scss"; } </code></pre> <p>あるフラグ変数(ここでは <code>$flag</code> ですが、実際はファイル中ではなく Gulp タスク内で管理)が <code>true</code> のときのみ <code>parts1.scss</code> を読み込む。</p> <pre><code class="scss">$flag: true; @if ($flag) { @use "parts1.scss"; } @else { @use "parts2.scss"; } </code></pre> <p>あるいは、フラグ変数の値によって読み込む Scss ファイルを切り替える。</p> <p>この部分について、どうにかできないか(本当にやりたいのは最初の例ですが、代替案として2つ目の例でブランクの <code>parts2.scss</code> をダミーとして用意する方法を考える)、と。</p> <h2 id="対処"><a href="#%E5%AF%BE%E5%87%A6">対処</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/63803090/sass-dynamic-import-based-on-environment">css - Sass dynamic import based on environment - Stack Overflow</a></li> </ul> <p>色々検索した結果、 <code>gulp-sass</code> の <code>includePaths</code> オプションを使えばそれらしいことができそうだ、ということが分かりました。</p> <p>今回はたまたま自分も <code>gulp-sass</code> を使用している前提で、しかも Scss 本体の変数ではなく Gulp タスク内で管理しているフラグによって、というのが希望だったのでこの形はぴったりでした (この方法でなければ、上記スレの上の方にあるように、フラグをいったん Scss ファイルに変数として出力し、それを読み込むことで伝播させようと考えていました)。</p> <pre><code class="javascript">const { src, dest } = require('gulp'); const plumber = require('gulp-plumber'); const notify = require('gulp-notify'); const sass = require('gulp-sass'); sass.compiler = require('sass'); const Fiber = require('fibers'); const autoprefixer = require('gulp-autoprefixer'); // dynamic import test const flag = true; // scssコンパイルタスク const scss = () => { let opt = { fiber: Fiber, outputStyle: 'compressed' }; // dynamic import test if (flag) { opt.includePaths = [ `src/scss/parts/enable` ] } else { opt.includePaths = [ `src/scss/parts/disable` ] } return src('src/scss/**/*.scss') .pipe(plumber({ errorHandler: notify.onError({ message: 'Error: <%= error.message %>', title: 'scss' }) })) .pipe(sass(opt).on('error', sass.logError)) .pipe(autoprefixer({ cascade: false })) .pipe(dest('dist/css')); }; module.exports = scss; </code></pre> <p>Scss のコンパイルタスクはこのような感じで。</p> <pre><code>src/  └ scss/ ├ .scssファイル やディレクトリ ├ import/ │ └ _index.scss │ └ parts/ ├ disable/ │ └ parts_hoge.scss └ enable/ └ parts_hoge.scss </code></pre> <p>このようなディレクトリ構造で、 <code>src/scss/import/_index.scss</code> から <code>src/scss/parts</code> の中の<code>enable</code> または <code>disable</code> のどちらかの <code>parts_hoge.scss</code> を読み込む、とした場合。</p> <pre><code class="scss">// dynamic import test @use "parts_hoge"; </code></pre> <p><code>src/scss/import/_index.scss</code> の記述はこれだけですが、 Scss のコンパイルタスクに記述されている変数 <code>flag</code> によって読み込む元のディレクトリの候補が <code>src/scss/parts/enable</code> または <code>src/scss/parts/disable</code> のどちらかに切り替わる、ということです。</p> <p>あとは <code>src/scss/parts/disable/parts_hoge.scss</code> は中身のないブランクのファイルにしておけば、 <code>flag</code> が <code>true</code> の場合のみ css が当たる、ということになります。</p> <p>出力される css の切り分けはできたので、とりあえずはこの方法でしょうかね。</p> <h2 id="参考"><a href="#%E5%8F%82%E8%80%83">参考</a></h2> <ul> <li><a target="_blank" rel="nofollow noopener" href="https://stackoverflow.com/questions/63803090/sass-dynamic-import-based-on-environment">css - Sass dynamic import based on environment - Stack Overflow</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://www.npmjs.com/package/sass">sass - npm</a></li> <li><a target="_blank" rel="nofollow noopener" href="https://github.com/sass/node-sass#includepaths">sass/node-sass: Node.js bindings to libsass</a></li> </ul> arm-band