Gatsby + WordPress にscssを導入

タイトル通りだが、WordPressを管理画面としたGatsbyプロジェクトに導入した際の備忘録。プロジェクト作成時にscssを入れていなかったので、既存の(割と)プレーンなプロジェクトに追加する流れ。

環境

  • MacOS
  • node -v
    `v20.10.0`
  • Gatsby version: 5.3.3

大まかな流れ

  1. npm install
  2. gatsby-config.ts追記
  3. 既存cssの解消
  4. scssの検証

1. npm install

何はなくとも公式を参照せよ

https://www.gatsbyjs.com/plugins/gatsby-plugin-sass/

npm install sass gatsby-plugin-sass

2. gatsby-config.ts追記

gatsby-config.tsのpulugins:[]内に追記

    {
      resolve: `gatsby-plugin-sass`,
      options: {
        sassOptions: {
          includePaths: ['src/styles/scss'],
        },
      },
    },

3. 既存cssの解消

src直下のstylesはこんな風にしたい

./src
│   略
├── styles
│   ├── css
│   │   ├── @wordpress
│   │   │   └── 略
│   │   ├── global.css
│   │   ├── normalize.css
│   │   └── style.css
│   └── scss
│       ├── _base.scss
│       ├── _error.scss
│       ├── _mixin.scss
│       ├── _variables.scss
│       └── style.scss
└── 略

ベースのstyle.scssはとりあえずこんな感じ

@charset "UTF-8";

// variables
@import 'variables';

// mixin
@import 'mixin';

// default styles
@import 'base';
// @import 'slick';

// 404
@import 'error';

そのため、まずstylesディレクトリを作成し、その中にcss、scss(新規作成)ディレクトリを突っ込む。scssは完全新規なので問題ないがcssはディレクトリ構造が変わるので諸々変えなければいけない。変えたのは、以下の2ファイルのみ(だったと思う)。いずれも../css/記載部分を../styles/css/に変えるだけ。

  • gatsby-browser.tsx
  • blog-post.tsx

gatsby cleanした後にgatsby developし、エラーが出たら都度直せばヨシ。

4. scssの検証

試しにblog-post-archive.txtで、style.scssが適用されるか見てみる。

// blog-post-archive.txt
  return (
    <Layout isHomePage>
      <Seo title="All posts" />

      <Bio />
      <p className="ham">ham</p>

      <ol style={{ listStyle: `none` }}>

適用前

// style.scss
.ham {
  color: red;
}
// blog-post-archive.txt
import '../styles/scss/style.scss'

適用された✌️

Vue3 + Viteでmaterial iconを使う

みんな大好きmaterial design icon(マテリアルアイコン) をVue3とViteの環境で使ってみたので、その備忘録。

Vite .config.jsに追記するのかと思っていたら、不要でした。
やり方は全部こちらに書いてありますが、一応。

https://www.npmjs.com/package/vue-material-design-icons

アイコンはこちらから探せます。

https://materialdesignicons.com/

インストール

npm i vue-material-design-icons

yarnの場合

yarn add vue-material-design-icons

インポート

import MenuIcon from 'vue-material-design-icons/Menu.vue';

components: {
  MenuIcon;
}

グローバルの場合

import MenuIcon from 'vue-material-design-icons/Menu.vue';

Vue.component('menu-icon', MenuIcon);

描画

<menu-icon />

Nuxt.jsでスクロールアニメーションを入れる- ライブラリ Animated on Scroll (AOS)

明けましておめでとうございます。

フロントエンドエンジニアリングを勉強する前はjQuery多用ユーザーだったので、VueではjQuery使わないの?えっじゃあアニメーションとかコーディングしなきゃいけないの!?と慌てふためく脆弱エンジニアでした。VueやNuxtではライブラリが充実しているんですね〜ありがたやありがたや。

というわけで、今回はNuxt.jsにスクロールアニメーションを実装します。ライブラリで。(倒置法)

参考サイト
https://michalsnik.github.io/aos/
https://zacheryng.com/nuxt-with-animated-on-scroll/

npm install aos --save

グローバルに使いたいので@/plugins/aos.jsに導入。

import Vue from 'vue'
import AOS from 'aos'
import 'aos/dist/aos.css'

Vue.use(
  AOS.init({
    once: true,
    disable: window.innerWidth < 640,
    duration: 750,
    easing: 'ease-out-quart',
  })
)

nuxt.configに追記

plugins: [
    { src: "@/plugins/aos", mode: "client" },
  ],
purgeCSS: {
    whitelist: ["aos-init", "aos-animate", "data-aos-delay", "data-aos-duration", "fade-up", "zoom-in"],
}

描画。(vuetify使っているのでplacementValいらなかったです…)

            <v-item-group>
              <v-row>
                <v-col v-for="item in serviceItems" :key="item.name">
                  <v-item
                    :data-aos="`${item.motionVal}`"
                    :data-aos-anchor-placement="`${item.placementVal}`"
                  >
                    <v-card
                      height="200"
                      class="d-flex align-center top_services_item"
                      >{{ item.name }}</v-card
                    >
                  </v-item>
                </v-col>
              </v-row>
            </v-item-group>
<script>
export default {
  data() {
    return {
      serviceItems: [
        {
          name: 'item1',
          contents: 'ここに説明が入ります。',
          placementVal: 'top-center',
          motionVal: 'fade-up',
        },
        {
          name: 'item2',
          contents: 'ここに説明が入ります。',
          placementVal: 'center-center',
          motionVal: 'fade-down',
        },
        {
          name: 'item3',
          contents: 'ここに説明が入ります。',
          placementVal: 'bottom-center',
          motionVal: 'fade-up',
        },
    }
  },
}
</script>        

[Nuxt.js]2.9以上 Google material icon(マテリアルアイコン)を使う

久しぶりにみんな大好きGoogle fonts.のmaterial icon(マテリアルアイコン) をNuxt(@nuxt/cli v2.15.8)で使おうと思ったら、変なところでハマりました。
やり方は全部こちらに書いてありますが、インストールするパッケージを間違えたので備忘録としてまとめておきます。

https://google-fonts.nuxtjs.org/setup

2.9以下はこちらを参照ください。

パッケージをインストール

https://www.npmjs.com/package/nuxt-material-design-icons-iconfont

yarn add nuxt-material-design-icons-iconfont
// Or npm:
npm install nuxt-material-design-icons-iconfont

nuxt.config.jsに追記

modules: [
  'nuxt-material-design-icons-iconfont',
],

head内linkへの設定は適用されませんでした。何でだろう。

    {
        rel: 'stylesheet',
        href: 'https://fonts.googleapis.com/icon?family=Material+Icons',
    },

vueファイルに書く

 <span class="material-icons">chevron_right</span>

参考
How to use material design icons in nuxt | stack overflow

スタイルの変更などはこちらで詳しく解説されています。
Material Icons(Google Font Icons)の使い方を解説!表示されない時に確認すべきポイントも

NuxtにSass-loaderを導入する

NuxtだってScssを使いたい。というわけで入れます。

Webpack確認

今回Nuxt2系(v2.15.8)を入れたのですが、Webpackはデフォルトでv4が入るのでしょうか。sass-loaderのv11.0.0以降はwebpackのバージョン5以上しか対応していないようなので、v10をインストールします。

webpackの確認は

npm list webpack

これでwebpackが5以上なら普通にインストールすればいいのですが、

npm install sass-loader node-sass --save-dev

あてくしのバージョンは4だったので10をインストールしました。

npm install --save-dev sass sass-loader@10

使い方

<style lang="scss">とすればOKです。

<style lang="scss">
.main {
  .title {
    font-size: 32px;
  }
}
</style>

共通化はassets/scss/common.scss作成して、nuxt.config.jsで読み込めばOKです。
common.scss

.wrapper {
  width: 1200px;
  margin: 0 auto;
}
a {
  text-decoration: none;
  transition: 0.3s;
  color: inherit;
  &:hover {
    opacity: 0.7;
  }
}

nuxt.config.js

// Global CSS: https://go.nuxtjs.dev/config-css
css: ['ant-design-vue/dist/antd.css', '~/static/assets/scss/common.scss'],

変数を定義

先ほど作成したscssフォルダに_variable.scssを作成し変数を定義した後,npm実行。

npm i @nuxtjs/style-resources

nuxt.config.jsに追記します。

  // Modules: https://go.nuxtjs.dev/config-modules
  modules: [
    // https://go.nuxtjs.dev/axios
    '@nuxtjs/axios',
    '@nuxtjs/style-resources', // ココ!
  ],
  styleResources: {
    scss: ['~/assets/scss/_variable.scss'], // ココ!
  },

vue3 componentの読み込み方

親要素からcomponent(コンポーネント)を読み込むときの手順を、復習。

まずは子componentを作成

コンポーネントはキャメルケース。
component/ChildComponent.vue

<template>
  <div class="child_component">
    <h2>This is child component</h2>
  </div>
</template>

読み込む親要素で<script>内にimportし、componentを記載する。

script内もキャメルケース。
views/Parent.vue

<script>
import ChildComponent from '@/components/ChildComponent.vue'

export default {
  name: 'parent',
  components: {
    ChildComponent,
  },
}
</script>

読み込む親要素で描画箇所を記述

描画箇所はスネークケース

<template>
  <div class="parent">
    <h1>Parent page</h1>
    <child-component></child-component>
  </div>
</template>

トラブルシューティング

親のパスは通っていますか?

router/index.jsに親を登録していないと、/parentのuriでページが見られません。

import { createRouter, createWebHistory } from 'vue-router'
import Parent from '../views/Parent.vue'


const routes = [
  {
    path: '/parent',
    name: 'parent',
    component: Parent,
  },
]

const router = createRouter({
  history: createWebHistory(),
  routes,
})

export default router

viteを使っていますか?

Viteを使用し、@でパスの指定をしたい場合は、別途設定が必要です。
vite.config.js

import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import path from 'path'

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue()],
  resolve: {
    alias: {
      '@': path.resolve(__dirname, './src'),
    },
  },
})

[vue3]main.jsでの.use()つなぎ方によるエラー

Vue3 + viteでvuexの設定をいじっている時に、エラーが出たのでその備忘録。
エラー文
Uncaught (in promise) TypeError: Cannot read properties of undefined (reading ‘state’)
↑を解決した後に、

Uncaught RangeError: Maximum call stack size exceeded

という別のエラーが出ました。一難去ってまた一難。

結論から言うと、main.jsのcreateApp(App).use()のチェーンの仕方が悪かったようです。

バージョン

  • MacOS
npm list
├── @vitejs/plugin-vue@3.2.0
├── axios@1.1.3
├── node-sass@7.0.3
├── sass-loader@10.3.1
├── sass@1.55.0
├── vite@3.2.1
├── vue-axios@3.5.2
├── vue-router@4.1.6
├── vue@3.2.41
└── vuex@4.0.2

エラーの出たコード01

.useで使うプラグインを全て1つの()に入れ、コンマで区切っています。

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
import VueAxios from 'vue-axios'

createApp(App).use(router, store, VueAxios, axios).mount('#app')

この際に出たエラー文

Home.vue:5 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'state')
    at Proxy._sfc_render (Home.vue:5:20)
    at renderComponentRoot (runtime-core.esm-bundler.js:898:44)
    at ReactiveEffect.componentUpdateFn [as fn] (runtime-core.esm-bundler.js:5631:57)
    at ReactiveEffect.run (reactivity.esm-bundler.js:187:25)
    at instance.update (runtime-core.esm-bundler.js:5745:56)
    at setupRenderEffect (runtime-core.esm-bundler.js:5759:9)
    at mountComponent (runtime-core.esm-bundler.js:5541:9)
    at processComponent (runtime-core.esm-bundler.js:5499:17)
    at patch (runtime-core.esm-bundler.js:5101:21)
    at ReactiveEffect.componentUpdateFn [as fn] (runtime-core.esm-bundler.js:5711:17)

stateがどうこう言われているので、一旦routerとstoreを引き離してみる。

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import store from './store'
import axios from 'axios'
import VueAxios from 'vue-axios'

createApp(App).use(router).use(store, VueAxios, axios).mount('#app')

これでエラーは消えます。

stackoverflowの回答者によれば、.useの引数は1番目は1つのみで、2番目以降はおまとめできるとのことでした。

the use method accept one plugin as first parameter and options (which si optional) as second one app.use(plugin, itsOptions)

Vuex Cannot read property ‘state’ of undefined


ちなみに全部.use()のチェーンを分けて記載すると、別のエラーが出ました。

Uncaught RangeError: Maximum call stack size exceeded
    at isPlainObject (utils.js:129:23)
    at assignValue (utils.js:287:9)
    at forEach (utils.js:261:10)
    at merge (utils.js:299:21)
    at assignValue (utils.js:290:21)
    at forEach (utils.js:261:10)
    at merge (utils.js:299:21)
    at assignValue (utils.js:290:21)
    at forEach (utils.js:261:10)
    at merge (utils.js:299:21)

実験してみると、2つ目のエラーは分けたことが原因なのではなく、VueAxios, axiosの順番で読み込まないといけないということだったみたいです。
NG

createApp(App).use(router).use(store).use(axios).use(VueAxios).mount('#app')

NG

createApp(App).use(router).use(store).use(axios, VueAxios).mount('#app')

OK

createApp(App).use(router).use(store).use(VueAxios, axios).mount('#app')

axiosとstoreは一緒に入れても問題ないようでしたが、気持ち悪いので分けました。

[Vue.js]Viteを導入してみる

早い早いと話題のVite(ヴィート)。フランス語で「素早い」の意味らしいです。
Webpackではアプリケーション起動前に、アプリ全体を走査し依存を解決→バンドルしたソースを出力という流れだったのに対し、ViteはNative ESModulesのimportを利用し、ブラウザから直接モジュールを読み込むことで高速化を実現しています。

モジュールバンドラーRollup を使用してコードをバンドル…とあるので、ノーバンドルツールと言われつつもバンドルしない訳ではないようです。

この辺りの解説はANTEZさんの記事やっぱりwebpackがわからない(エピソード1)が超絶わかりやすかったです。

プロジェクト作成

前提

Viteを使うには、Node.jsが14.18+、16+でなければなりません。

% cd projects
% npm create vite@latest
Need to install the following packages:
  create-vite@3.2.0
Ok to proceed? (y) y
✔ Project name: … vite-app
✔ Select a framework: › Vue
✔ Select a variant: › JavaScript

Scaffolding project in /Users/meow/Documents/projects/vite-app...

プロジェクト名や使用するテンプレートはオプションでも指定可能。

# npm 6.x
npm create vite@latest my-vue-app --template vue

とりあえず起動

npm install
npm run dev

テーン!!

後からわかったのですが、`npm create vite’でプロジェクト作成した時はstoreやらrouteやらを自分で入れなければいけないみたいですね。というわけでこちらにまとめました。

Vite / vue.js / vue3

ほか参考

Vite

 [VSCode, Prettier]勝手にダブルクォーテーションにしないで

VSCodeでプロジェクトをクローンしてきたら、保存時にPrettierさんがシングルクォーテーション(”)をダブルクォーテーション(””)に変えてくれていました(嫌味)。
どちらがいいかはまあ…宗派や使用しているツールに依る思いますが、既存のプロジェクトで勝手に変えられるのは困ります。

と言うわけで設定を変更。
Setting (Ctrl + ,)の検索窓から「Quote」で検索し、検索結果のサイドメニューからPrettierを選択。

2つのチェックボックスにチェックを入れます。

お疲れ様でした。

と思いきや

全然直ってませんでした。

Prettierの設定ファイルを作成

プロジェクトディレクトリ直下に.prettierrcファイルを作成し、

以下を記述。

{
  "singleQuote": true,
}

今度こそ直りました。

他にも希望の設定を付け足せます。

{
  "semi": false,
  "arrowParens": "always",
  "trailingComma": "es5",
  "singleQuote": true,
  "quoteProps": "preserve",
  "endOfLine": "auto"
}

参考

https://stackoverflow.com/questions/48864985/vscode-single-to-double-quote-automatic-replace


Quotation mark (引用符) / シングルクォーテーション(”) / ダブルクォーテーション / VSCode / Prettier

SourceMap(ソースマップ)ってなんぞ

gulpを使ってみて、gulp-sourcemapsというモジュールが便利そうだったので調べたことをメモ。そもそもSouceMapとは何か。

ソースマップとは

ブラウザで利用されているJavaScriptはコンパイルされているが、何かエラーが起こった際に、コンパイルされたままだとエラー箇所がよくわからず、不便。そのため、最適化やコンパイルされる前のJavaScriptを保持したソースファイルを作っておくと、後々便利、といったもの。

source map is a file that maps from the transformed source to the original source, enabling the browser to reconstruct the original source and present the reconstructed original in the debugger.
To enable the debugger to work with a source map, you must:
generate the source map
– generate the source map
– include a comment in the transformed file, that points to the source map. The comment’s syntax is like this:
//# sourceMappingURL=http://example.com/path/to/your/sourcemap.map

Use a source map

意訳:
ソースマップはオリジナルファイルから変換されたソースをマップしたファイルで、ブラウザがオリジナルのソースを再構築し、その再構築されたオリジナルをデバッガーに表示できるようにするものだ。
ソースマップでそのデバッガーを有効にするには、ソースマップを生成する必要がある。

  • まず、ソースマップを生成
  • 再構築されたファイル内に、ソースマップを指定するコメントを記述

コメントは以下の形式

//# sourceMappingURL=http://example.com/path/to/your/sourcemap.map

こうなることも想定

//# sourceMappingURL=main.js.map

動画でも解説あり。
https://youtu.be/Fqd15gHC4Pg

In the video above we load https://mdn.github.io/devtools-examples/sourcemaps-in-console/index.html. This page loads a source called “main.js” that was originally written in CoffeeScript and compiled to JavaScript. The compiled source contains a comment like this, that points to a source map:
//# sourceMappingURL=main.js.map
In the Debugger’s source list pane, the original CoffeeScript source now appears as “main.coffee”, and we can debug it just like any other source.

Use a source map

以下も意訳。元記事・動画はFirefoxを使っているが、意訳ではChromeを使用した場合の記載に書き換えている。

例えば、こちらのサンプルページ。
https://mdn.github.io/devtools-examples/sourcemaps-in-console/index.html

検証ツール-> Sources を開き、jsフォルダの中身を見てみよう。
このページでは、もともとCoffeeScriptで書かれ、コンパイルされたmain.jsというJavaScriptを読み込んでいる。このコンパイルされたソースコードには以下のコメントが挿入されており、これがソースマップを指しているのだ。

//# sourceMappingURL=main.js.map

デバッガーのSourcesパネルには、オリジナルのソースであるmain.coffeeが表示されており、まるで別のソースをいじるかのようにして、我々はこのソースをデバッグできるのである。

以上メモおしまい