Motomichi Works Blog

モトミチワークスブログです。その日学習したことについて書いている日記みたいなものです。

rails5 + webpacker4 + vue-loader15.7.0 で単一VueコンポーネントにSCSSを書く

参考にさせていただいたページ

はじめに

webpackerよくわからなくてハマったときのメモです。

config/webpack/loaders/vue.js

webpackであれば、webpack.config.jsのrulesに書くことを、webpackerではファイルごとに分けてからrequireする例がよく出てきます。

config/webpack/loaders/vue.jsに以下のように記述します。

module.exports = {
  test: /\.vue(\.erb)?$/,
  use: [{
    loader: 'vue-loader'
  }]
}

今回、特にmini-css-extract-pluginなどは設定していません。

config/webpack/loaders/sass.jsはいらない

なんかWebで検索すると、以下のようなファイルを作成するような情報が出てきたりしますが、どうもいらないみたいでした。

  • config/webpack/loaders/sass.js
  • config/webpack/loaders/scss.js

config/webpack/*.js

webpackerだと、以下のような感じでwebpack.config.jsにあたるファイルがあると思います。

  • config/webpack/environment.js
  • config/webpack/development.js
  • config/webpack/production.js
  • config/webpack/test.js

例えばconfig/webpack/environment.jsに、さきほどのconfig/webpack/loaders/vue.jsを以下の感じでrequireして使います。

const { environment } = require('@rails/webpacker')
const { VueLoaderPlugin } = require('vue-loader')
const vue = require('./loaders/vue')

environment.plugins.prepend('VueLoaderPlugin', new VueLoaderPlugin())

environment.loaders.prepend('vue', vue)

environment.jsの記述内容については色々省略してvue-loaderに関係あるところだけ書いています。

html.erb

layoutsの方ではなく、各ページごとのerbに以下のような感じで書きます。

単一Vueコンポーネントファイルの<template><script>だけが必要な場合はjavascript_pack_tagだけで良いのですが、どうやら<style>も必要な場合はstylesheet_pack_tagの方も書く必要があるようです。
このpathはどちらも同じだと思います。

<% content_for :javascript do %>
  <%= stylesheet_pack_tag "path/to/your/js/entry/point" %>
  <%= javascript_pack_tag "path/to/your/js/entry/point" %>
<% end %>

.vueファイル

.vueファイルは例えばこんな感じで書きます。 <%= stylesheet_pack_tag "path/to/your/js/entry/point" %>を書いて、<style></style>のタグを書いておかないとエラーになりますので注意が必要です。

<template>
  <div class="hoge">hoge</div>
</template>

<script>
〜略〜
</script>

<style lang="scss" scoped>
.hoge {
  background: #ff0000;
  font-size: 100px;
  font-weight: bold;
}
</style>

書き出されるHTML

上記したerbがHTMLとして書き出されると、scriptタグとlinkタグはたぶん以下のような感じになると思います。

<script src="/packs/js/path/to/your/js/entry/point-41708a9247d43d8ca518.js"></script>
<link rel="stylesheet" media="screen" href="/packs/css/path/to/your/js/entry/point-36141da8.css">

scssを@importする場合のpath

<style lang="scss" scoped>
@import './app/frontend/path/to/your/file';
</style>

とか

<style lang="scss" scoped>
@import './app/frontend/path/to/your/file.scss';
</style>

みたいな感じでimportできました。

Nuxt.js 2.x + TypeScript 4.x その0010 FontAwesome5のアイコンをpropsから渡すときの型を設定する

はじめに

以前書いた「Nuxt.js 2.x + TypeScript 4.x その0004 FontAwesomeの必要なアイコンだけ読み込んで使う - Motomichi Works Blog」みたいな感じでimportしたアイコンを、例えば自分で作ったMyComponentに渡すときにMyComponentのpropsの型はどのように設定するかという話です。

上記の記事でcomputedにfaSearchを定義していますが、これは既にIconDefinition型が設定されています。

MyComponentに渡したアイコンもIconDefinition型として扱いたいというわけです。

今日の開発環境

  • Nuxt 2.14.12
  • TypeScript 4.2.3

IconDefinition型が定義されているファイルを探す

node_modulesディレクトリ内を探してみると、node_modules/@fortawesome/fontawesome-common-types/index.d.ts の中に定義されていました。

MyComponentのpropsに型を設定する

以下のような感じでimportします。

import Vue, { PropType } from 'vue'
import { IconDefinition } from '@fortawesome/fontawesome-common-types/index'

以下のような感じで型を設定しました。

props: {
    icon: {
      type: Object as PropType<IconDefinition>,
      required: false,
      default: () => null,
    },
},

this.iconが以下のように型推論されるようになりました。

f:id:motomichi_works:20210523011958p:plain

Nuxt.js 2.x + TypeScript 4.x その0009 Sassの変数やmixinを全てのコンポーネントで使えるようにする

参考にさせていただいたページ

style-resources-module のインストール

GitHub - nuxt-community/style-resources-module: Nobody likes extra @import statements!」にある通り、Sassは予めインストールして使える状態にしておきます。

以下のコマンドでインストールします。

yarn add -D @nuxtjs/style-resources

nuxt.config.jsの編集

GitHub - nuxt-community/style-resources-module: Nobody likes extra @import statements!」の最新情報を参照してください。

公式のREADMEの「SCSS Example」の項を参考にnuxt.config.jsを編集します。

export default {
  buildModules: ['@nuxtjs/style-resources'],
  styleResources: {
    scss: [
      './assets/vars/*.scss',
      './assets/abstracts/_mixins.scss' // use underscore "_" & also file extension ".scss"
      ]
  }
}

TypeScript学習日記 その0005 TypeScriptのバージョンを確認する(tscのバージョンを確認する)

参考にさせていただいたページ

確認方法

以下のコマンドで確認できると思います。

npx tsc -v

Nuxt.js 2.x + TypeScript 4.x その0008 Vue.extend()でやっている場合のmixin

はじめに

検索すると、クラスベースで書いてデコレータを使う方法については多くヒットしますが、Vue.extend()で書いている場合の方法についてはあまりヒットしなかったのでこの記事を書いています。

特に変わったことは書いていませんが。

今日の開発環境

  • Nuxt 2.14.12
  • TypeScript 4.2.3

my_mixin.tsの作成とその記述内容

例えば以下のような感じでmy_mixin.tsを作成します。
mixinもコンポーネントを作成する場合と同じく Vue.extend() することで正しく型推論されるようになります。

import Vue from 'vue'

export default Vue.extend({
  computed: {
   myComputed() {
      return 'myComputed'
    },
  },
})

my_mixin.tsをimportする側のコンポーネントの作成とその記述内容

例えば以下のような感じでコンポーネントのファイルmy_component.vueを作成します。

<template>
  〜略〜
</template>
<script lang="ts">
import Vue from 'vue'

import myMixin from '~/mixins/my_mixin'

export default Vue.extend({
  name: 'MyComponent',
  mixins: [myMixin],
  computed: {
    hoge() {
      return 'hoge'
    },
  },
})
</script>
<style lang="scss" scoped>
  〜略〜
</style>

おまけ

以下のページに (this as InstanceType<typeof adIdMixin>) といったように、Type Assertionをすると良いようなことが書いてあります。

私は今のところそのようなことをしなくても正常に型推論されていますが、どなたかの参考になるかも。

TypeScript 学習日記 その0004 関数の型を定義する

参考にさせていただいたページ

はじめに

いくつか方法がありますが、少し書いてみます。

後日もう少し充実させていこうと思います。

例として、以下のような「引数が2つあってオブジェクトを返す関数」の型を定義してみます。

    const myFunction = function (arg1, arg2) {
      return {
        a: arg1,
        b: arg2,
      }
    }

引数arg1はstring型、引数arg2はnumber型を想定しています。

typeキーワードを使う基礎的な方法

まずは基礎的な方法で定義してみます。

    // 型を定義
    type MyFunction = ( arg1: string, arg2: number ) => {
      a: string
      b: number
    }

    // 関数を定義して型を適用
    const myFunction: MyFunction = function (arg1, arg2) {
      return {
        a: arg1,
        b: arg2,
      }
    }

    // 実行
    const example = myFunction('str', 111)
    console.log('returnValue: ', example) // { a: 'str', b: 111 }

JavaScriptでアロー関数を書くときの記法と似ています。 あくまでも型の定義なので、=>の右側はオブジェクトであっても丸括弧でくくったり、returnキーワードを付けたりはしません。

Genericsを使って定義する

Genericsを使って同じ型を定義してみます。

    // 型を定義
    type MyFunction<T1, T2, T3> = (arg1: T1, arg2: T2) => T3

    // 関数を定義して型を適用
    const myFunction: MyFunction<
      string,
      number,
      {
        a: string
        b: number
      }
    > = function (arg1, arg2) {
      return {
        a: arg1,
        b: arg2,
      }
    }

    // 実行
    const returnValue = myFunction('ttt', 111)
    console.log(returnValue)

Genericsを使って定義した型は、使用するときに型引数を渡すことができます。

この例では型引数T1、T2、T3を渡しています。

渡されたT1、T2、T3はそれぞれ (arg1: T1, arg2: T2) => T3 という風に適用されます。

さきほどの「typeキーワードを使う基礎的な方法」と見比べるとよく理解できると思います。

引数の型が決まっていない関数を定義する(関数実行時に引数の型が決まる関数を定義する)

TypeScript 学習日記 その0008 引数の型が決まっていない関数を定義する(関数実行時に引数の型が決まる関数を定義する) - Motomichi Works Blog」に別途書きました。

TypeScript 学習日記 その0003 文字列が入っている配列を元にStringLiteralTypesの型を定義する

参考にさせていただいたページ

Template Literal Typesについて

配列を元にStringLiteralTypesの型を定義する方法について

はじめに

以下のように記述すると、変数myStringには 'aaa' または 'bbb' または 'ccc' のいずれかだけが代入できるようになります。

    const myString: 'aaa' | 'bbb' | 'ccc' = 'aaa'

この型を配列を元に定義したい。ということです。

配列を元にStringLiteralTypesの型を定義する方法

以下のようにするとできます。

    const myArray = ['aaa', 'bbb', 'ccc'] as const
    type MyStringLiteralType = typeof myArray[number]

    const myString: MyStringLiteralType = 'aaa'