技術ブログ

(技術系中心)基本自分用備忘録なので、あくまで参考程度でお願いします。

webpackまとめ

webpackとは

webpackとはモジュールバンドラーになります。

webpacklを利用することで、複数のモジュールを依存関係を解決して一つのアセットにまとめることが出来ます。(下記イメージ図)

f:id:lhiroki1205:20210722130411p:plain

webpackメリット

  • モジュールを一つにまとめることで、パフォーマンスを落とさずにHTTP通信が可能になる
  • スクリプトの読み込み順番とかの依存関係をwebpackでまとめることが出来る
  • 外部モジュール(npmとかでインストールしたもの)もバンドリングすることができる

webpackデメリット

  • 概念理解が難しい
  • webpack.config.js の設定がややこしい

webpackインストール

npm initでpackaje.jsonを作成する。 npm install webpack webpack-cliでwebpck本体とCLIを同時にインストールする。

webビルド

npx webpackでビルドすることが可能です。

npx webpack --mode development でdevelopmentoモードでビルドすることができる。

※ npxとは npmとnpx。なにが違う?

webpack.config.js

バンドリングの説明などの設定を記載するファイル。

webpackを理解する上で一番大事な箇所。

webpack.config.jsには大量の設定項目がありますが、まずは4つの中心的な項目について理解する必要があります。

■ Entry

webpackがビルドを始める際の開始点となるjsファイル。 モジュールやライブラリの依存関係を判断、処理してくれます。

const path = require('path')

module.exports = {
    entry: path.resolve(__dirname, "entry.js"),
}

■ Output

bundleファイルをwebpackがどこにどのような名前で出力すればいいのかを指定できます。

distディレクトリの中にbundle.jsという名前で出力するとしたら次のようになります。

__dirnameディレクト名称になります。

const path = require('path')

module.exports = {
    entry: path.resolve(__dirname, "entry.js"),
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    }
}

■ Loaders

webpack自身はJavaScriptしか理解できませんが、Loaderを使うことによってJavaScript以外のものも処理できるようになります。

  1. testプロパティに拡張子を指定して、あるLoaderがどのような種類のファイルを処理するべきなのか特定する(正規表現で拡張子を指定)。下記の例で言うと、拡張子が.txtのものを指定している。

  2. useプロパティにLoaderを指定して、testプロパティに指定したファイルがアプリケーションの依存関係や最終的なbundleファイルに加えられるように変換する。下記の例で言うと、txtファイルの場合はbundleファイルに追加する前にraw-loaderで変換する。

const path = require('path')

module.exports = {
    entry: path.resolve(__dirname, "entry.js"),
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    module: {
        rules: [
            { test: /\.txt$/, use: 'raw-loader' }
        ]
    }
}

■ Plugins

Pluginはwebpackができることの幅を広げてくれます。

こんなプラグインが存在します。

プラグインを利用する場合はrequireして、plugins配列に追加します。

const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')

module.exports = {
    entry: path.resolve(__dirname, "entry.js"),
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js'
    },
    module: {
        rules: [
            { test: /\.txt$/, use: 'raw-loader' }
        ]
    },
    plugins: [
        new webpack.optimize.UglifyJsPlugin(),
        new HtmlWebpackPlugin({template: './src/index.html'})
    ]
}

参考

Concepts | webpack

#1 わかりにくいwebpackをわかりやすく解説! - YouTube

webpack.config.jsがわからない - Qiita

:isで動的にコンポーネントを変更する方法

:isで動的にコンポーネントを変更する方法

動的にコンポーネントを変更する方法としてv-ifを利用する方法がありますが、コンポーネントの数が増えてくると非常に手間になります。

その時に便利なのが:isを利用してパラメーターによってコンポーネントを変更する方法です。

例)テンプレート側

<div>

<!--ここで読み込むコンポーネントが動的に変わる-->
<component :is="currentHeader">

<slot></slot>
<footer>同じ内容</footer>
</div>

例)JS側

import IndexHeader from './IndexHeader.vue'
import SearchHeader from './SearchHeader.vue'
import ArchiveHeader from './ArchiveHeader.vue'

export default {
 props: ['currentHeader'],
 components: {
   Index: IndexHeader,
   Search: SearchHeader,
   Archive: ArchiveHeader
 }
}

jp.vuejs.org

Type Scriptの型(基本)

Type Scriptの型(基本)

// 型推論の場合は型を定義しなくてもOK
let hasValue = true;
let count = 10;
let float = 3.14;
let negative = -0.12;
let single = 'hello';
let double = "hello";
let back = `hello`;

// 型注釈の場合は型を定義する
let hello: string;
hello = 'hello';

// オブジェクトに型を定義する
const person: {
  name: string
  age: number
} = {
  name: 'jack',
  age: 21
}

// 配列に型を定義する
const fruits: string[] = ['Apple', 'Banana', 'Grape'];

// tuple型を定義する(型定義以外のものがくればエラーになる。より厳密にしたい場合に利用する)
const book: [string, number, boolean] = ['business', 1500, false];

// enum定義もできる
enum CoffeeSize {
  SHORT,
  TALL = 'TALL',
  GRANDE = 1,
  VENTI
}

const coffee = {
  hot: true,
  size: CoffeeSize.TALL
}
coffee.size = CoffeeSize.SHORT;

// anyはなんでも入れる事が出来る(TypeScriptの恩恵を受けれないので基本は利用しないようにする)
let anything: any = true;
anything = 'hello';
anything = ['hello', 33, true];
anything = {};
anything.fjiafjaj = 'faijfi';
let banana = 'banana';
banana = anything;


// unionは複数の型を定義できる
let unionType: number | string = 10;
let unionTypes: (number | string)[] = [21, 'hello']


// unionとliteralを同時に使え
// typeエイリアスを利用して複雑な型を変数のように扱う
type ClothSize = 'small' | 'medium' | 'large';
const apple = 'apple';
let clothSize: ClothSize = 'large';
const cloth: {
  color: string;
  size: ClothSize
} = {
  color: 'white',
  size: 'medium'
}


// 関数に型をつけることも可能
// パラメーターの後(第二引数)に戻り値の型を指定する
function add(num1: number, num2: number): number {
  return num1 + num2
}

// 関数の戻り値にvoidをすると何も返さない(undefined)という意味になる
function sayHello(): void {
  // console.log('Hello!');
}

// console.log(sayHello());
let tmp: undefined;



// 関数型を使えば特定の関数のみ代入できる変数を作成できる
const anotherAdd: (n1: number, n2: number) => number = function (num1, num2) {
  return num1 + num2
};
// アロー関数で書く場合
const doubleNumber: (num: number) => number = num => num * 2;


// callback関数に型をつけることもできる
function doubleAndHandle(num: number, cb: (num: number) => void): void {
  const doubleNum = cb(num * 2);
  // console.log(doubleNum);
}

doubleAndHandle(21, doubleNum => {
  return doubleNum
});

// unknownはanyと一緒でなんでも入れられる
let unknownInput: unknown;
let anyInput: any;
let text: string;
unknownInput = 'hello';
unknownInput = 21;
unknownInput = true;
text = anyInput;
if (typeof unknownInput === 'string') {
  text = unknownInput;
}

function error(message: string) {
  throw new Error(message);
}
console.log(error('This is an error'));

Cloud Build is 何?

Cloud Build is 何?

Cloud Build は、Google Cloud Platform のインフラストラクチャでビルドを行うサービスです。 Cloud Build は、さまざまなリポジトリクラウド ストレージ スペースからソースコードをインポートし、仕様に合わせてビルドを実行し、Docker コンテナや Java アーカイブなどのアーティファクトを生成できます。

簡単に言うとGCPが提供するCIツールの一種になります。

GCPに特化したビルドサービスがCloud Buildになる感じです。

料金

フルマネージドのサービスで、1分あたりの料金も$0.003と非常に安く、1 日あたり120分は無料

デプロイイメージ

CludBuild設定

Cloud Build で必要なものは主に以下になります。

1. トリガー
2. リポジトリ/ブランチ(git 関連)
3. ビルド実行用ファイル
4. Dockerfile

例) 1. 任意のブランチからSource Repositories に対してgit push 2. 事前にCloud Build のトリガーを作成し、git push を検知してトリガーを実行 3. コンテナイメージをビルドして、Container Registry にpush 4. push したイメージを元にGKE にコンテナをデプロイ

参考

cloud.google.com

gurutaka-log.com

ffiインストールエラー対策

bundle installで下記のエラーが出る

1 error generated.
make: *** [Function.o] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/inouehiroki/ghq/github.com/SchooLynk/schoolynk-intelligence-api/vendor/bundle/ruby/2.6.0/gems/ffi-1.11.1 for inspection.
Results logged to /Users/inouehiroki/ghq/github.com/SchooLynk/schoolynk-intelligence-api/vendor/bundle/ruby/2.6.0/extensions/-darwin-20/2.6.0/ffi-1.11.1/gem_make.out

An error occurred while installing ffi (1.11.1), and Bundler cannot continue.
Make sure that `gem install ffi -v '1.11.1' --source 'https://rubygems.org/'` succeeds before bundling.

In Gemfile:
  guard-rspec was resolved to 4.7.3, which depends on
    guard was resolved to 2.15.1, which depends on
      listen was resolved to 3.1.5, which depends on
        rb-inotify was resolved to 0.10.0, which depends on

gem install ffi -v '1.11.1' --source 'https://rubygems.org/'と言われているので実施する

➜  schoolynk-intelligence-api git:(master) gem install ffi -v '1.11.1' --source 'https://rubygems.org/'
Building native extensions. This could take a while...
ERROR:  Error installing ffi:
    ERROR: Failed to build gem native extension.

    current directory: /Users/inouehiroki/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/ffi-1.11.1/ext/ffi_c
/Users/inouehiroki/.rbenv/versions/2.6.6/bin/ruby -I /Users/inouehiroki/.rbenv/versions/2.6.6/lib/ruby/2.6.0 -r ./siteconf20210605-43335-vyqlly.rb extconf.rb
checking for ffi_call() in -lffi... yes
checking for ffi_closure_alloc()... yes
checking for shlwapi.h... no
checking for rb_thread_call_without_gvl()... yes
checking for ruby_native_thread_p()... yes
checking for ruby_thread_has_gvl_p()... yes
checking for ffi_prep_cif_var()... yes
checking for ffi_raw_call()... yes
checking for ffi_prep_raw_closure()... yes
creating extconf.h
creating Makefile

current directory: /Users/inouehiroki/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/ffi-1.11.1/ext/ffi_c
make "DESTDIR=" clean

current directory: /Users/inouehiroki/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/ffi-1.11.1/ext/ffi_c
make "DESTDIR="
compiling AbstractMemory.c
compiling ArrayType.c
compiling Buffer.c
compiling Call.c
compiling ClosurePool.c
compiling DynamicLibrary.c
compiling Function.c
Function.c:867:17: error: implicit declaration of function 'ffi_prep_closure' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    ffiStatus = ffi_prep_closure(code, &fnInfo->ffi_cif, callback_invoke, closure);
                ^
1 error generated.
make: *** [Function.o] Error 1

make failed, exit code 2

Gem files will remain installed in /Users/inouehiroki/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/gems/ffi-1.11.1 for inspection.
Results logged to /Users/inouehiroki/.rbenv/versions/2.6.6/lib/ruby/gems/2.6.0/extensions/-darwin-20/2.6.0/ffi-1.11.1/gem_make.out
Function.c:867:17: error: implicit declaration of function 'ffi_prep_closure' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
    ffiStatus = ffi_prep_closure(code, &fnInfo->ffi_cif, callback_invoke, closure);

このエラーの対策

export PKG_CONFIG_PATH="/opt/homebrew/opt/libffi/lib/pkgconfig"

参考:

Mac M1 Big Sur にRuby / Railsをインストール 2021-01 - Qiita

vuex-persistedstateハマりポイント(Vuex)

vuex-persistedstateハマりポイント(Vuex)

vuex-persistedstateがイケてなくてリロード時にgettersでnullになった話

■ 原因 ローカルストレージ→storeのコピーがmounted()の後にコピーされる

■ 対策 nuxt-client-init-moduleをインストールする。

これで “nuxtClientInit” という関数でクライアントが初期がしたときの動作を定義できる

参考

【Nuxt.js】vuex-persistedstateがイケてなくてリロード時にgettersでnullになった話 | のうみそブログ

続きを読む