tomatoaiuの日記

やったこと や まなんだこと をまとめたい

【Electron】 electron-builderで静的なファイルをパッケージングした後に対象のファイルが無いと怒られないようにする

モチベーション

ソースコード内で静的なファイル(画像など)を読み取るアプリケーションをelectron-builderでパッケージングして、作成したアプリを起動するとそのファイルが無いとエラーが出る。躓きポイント。

build構成

解決策

ここに書いてある。
例えばpackage.jsonと同じ階層にimagesというフォルダがあったとする。これをソースコード内で利用している場合を想定。

package.json
images/
  hoge.png
  fuga.jpg

この時に、node.jspackage.jsonに、"build": { "files": ["images/"] }みたいに書いてビルドすればok!

{
  "name": "foobarbaz-app",
  "version": "0.0.1",
  "build": {
    "files": [
      "images/"
    ],
〜略〜

思ったこと

package.jsonfilesみたいな感じだと思われる。

参考文献

【Electron】electron-builderでのexeファイルの位置をelectron-logで書き出す

モチベーション

electron-builderでのパッケージング時に、portableを指定している場合の作成されたexeファイルの位置を知りたい。これをどうするのかで結構悩んだ。

実装失敗

以下のように5つの方法でやってみる。

import * as log from 'electron-log';
import * as path from 'path';

log.debug(app.getPath('exe'));
log.debug(app.getPath('module'));
log.debug(process.cwd());
log.debug(__dirname);
log.debug(path.resolve(''));
C:\Users\<user>\AppData\Local\Temp\<randomな文字>\electron-sample.exe
C:\Users\<user>\AppData\Local\Temp\<randomな文字>\electron-sample.exe
C:\Users\<user>AppData\Local\Temp\<randomな文字>
C:\Users\<user>\AppData\Local\Temp\<randomな文字>\resources\app.asar\dist
C:\Users\<user>\AppData\Local\Temp\<randomな文字>

どれもportableで作成したexeの位置ではない。portableで作成したexeファイルを実行した時に作成されるexeファイルの位置ならこれでokなんだけどね。

実装成功

ここに乗っていた。

import * as log from 'electron-log';

log.debug(process.env.PORTABLE_EXECUTABLE_DIR);
C:\Users\<user>\development\<electron-sample>\release

やったぜ!!

おまけ

以下のようにすることで、electron-builderでパッケージング後に出力されたexeファイルの位置にログファイルが出力されるはず。

const path = process.env.PORTABLE_EXECUTABLE_DIR;
log.transports.file.level = path;

気をつけたいことが、$ electron ./main.js等をした時には、exeファイルがまだないのでエラーが出ること。なので、開発モードとプロダクションモードでいい感じにコードを切り分ける必要がある。

参考文献

【scp】Scpを使ってMac OSからファイルをCentOSにアップロードする

この方法にたどり着くまで、いろんなssh系のクライアントを入れて、あーでもない、こーでもないの模索していました。

環境

  • Host: CentOS ip: 192.168.33.33
  • Local: MacOS Mojave
  • 送信するファイル: file.txt

ファイルアップロード

こんなコマンドで、動いた。

scp ./file.txt "hogeaccount@192.168.33.33:~/"

こんな感じのシンタックス

scp <source_filepath> "<account>@<ipadress>:<dist_path>"

気をつけること

ipadressとdist_pathの間は、:で繋ぐこと。
これが大事。

React.jsのuseMemoはVue.jsのcomputedに近いのではないかという説

React.jsを触らないといけない今日この頃。useMemoというhookに出会った。これはメモ化した値を返してくれるやつ。漠然とキャッシュで値を保持できて、いろんなものの表示速度が上がるのかなって思ってた。
だけど、それ以外にも、Vue.jsのcomputedみたいに値を加工して値を返すみたいなことができることに気づいた。やっと気づいたのこの考え方によりReact.jsの初心者として一歩進めた気がした。

React.jsのuseMemoがVue.jsのcomputedみたいな感じに見える例:

正しく動くかは置いといて。以下のコードは、stateから何か値を取得して、新しい値を返す仕組み。 }, [state]);と書くことによって、stateに変更がある度に、oksが再計算されて新しい加工した値を返してくれる。

function App() {
  const { state, dispatch } = useReducer(reducer, initialState);
  const oks = useMemo(() => {
    return state.fuga.filter(f => f.done);
  }, [state]);

  return (
    <div>
      {
        oks.map((f) => (
          <p>{f.name}</p>
        ))
      }
    </div>
  )
}

まとめ

この使い方がuseMemoの正しい使い方は分からないが、今後は使っていきたい。

ちなみにVue.jsのcomputed

これも正しく動くかは分からないけど。書いとく。

<template>
  <div>
    <p v-for="f in oks">{{ f.name }}</p>
  </div>
</template>

<script>
export default {
  props: ['state'],
  computed: {
    oks: () => this.state.fuga.filter(f => f.done)
  }
}
</script>

React.jsでhookを使ってみる【04】|useMemo, useCallback

useMemoとuseCallback

この2つは結構使われているのかな。なかなか簡単に学べるものでは無い気がする。主にはメモ化するときに使うみたい。でもメモ化ってなんだろうか?

メモ化

wikiに書いてあった。
関数のキャッシュのようなものなのかな。

useMemo

せっかくだから使ってみる。正しく使えているのかはわからないけど。

import React, { useState, useMemo } from 'react';

function App() {
  const [count, setCount] = useState(0);
  const value = useMemo(() => {
    return Math.sqrt(10000000);
  }, []);

  return (
    <div>
      <p>{ value }</p>
      <p>{ count }</p>
      <button onClick={() => { setCount(count + 1); }}>+ 1</button>
    </div>
  )
}

export default App;

こんな感じにすると、ボタンが押されてもvalueが再計算されない。つまりメモ化できてる???

useCallback

これも使ってみる。同じく正しく使えているのかはわからないけど。

import React, { useState, useCallback } from 'react';

function App() {
  const [count, setCount] = useState(0);
  const click = useCallback(() => {
    return setCount(c => c + 1)
  }, []);

  return (
    <div>
      <p>{ count }</p>
      <button onClick={click}>+ 1 memo</button>
    </div>
  )
}

export default App;

参考文献

React.jsでhookを使ってみる【03】|useReducer

今回もhookを使ってみる。

useReducer

reduxを簡単に実装できるのかな?調べながら書いてみた。

import React, { useContext, useReducer } from 'react';

const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

const CountDispatch = React.createContext(null);

function App() {
  const [state, dispatch] = useReducer(reducer, initialState);

  return (
    <>
      Count: {state.count}
      <CountDispatch.Provider value={dispatch}>
        <IncrementButton />
        <DecrementButton />
      </CountDispatch.Provider>
    </>
  );
}

function IncrementButton() {
  const dispatch = useContext(CountDispatch);

  function handleClick() {
    dispatch({type: 'increment'});
  }

  return <button onClick={handleClick}>+ 1</button>
}

function DecrementButton() {
  const dispatch = useContext(CountDispatch);

  function handleClick() {
    dispatch({type: 'decrement'});
  }

  return <button onClick={handleClick}>- 1</button>
}

export default App;

これで無事に動いた。useContextとuseReducerを合わせながら書くといいのかもしれない。知らんけど。この辺りの知見が全く無いので今後調べてブログに書きたい。

参考文献

React.jsのhookを使ってみる【02】|useContext

今日もhookを使ってみる。

useContext

これ何に使うんだろう。

const value = useContext(MyContext);

サンプルで1行載ってた。
つまりどういうことなんだ?
調べてみる。

createContext()

こういうメソッドがあるらしい。useContextはこれをhookとして使えるようにしたものみたい。バケツリレーを回避するアプローチなのかな。 親側で定義したものを間を意識せず子供側で利用できるみたい。これは、好きかって親で定義してしまって、子供でも好き勝手使ってしまえるのでは? 重複して定義してしまったらどうなるんだろうか?いろいろ疑問が出る。

しかし、たまに同じデータがツリー内の異なるネスト階層にある多くのコンポーネントからアクセス可能であることが必要となります。

これを読むと、本当に限られたところでしか使うべきではないってことなのかな。よくよく読んでくと重複はできないようになっているっぽい。それに、

ツリー内の最も近い上位の一致する Provider から現在のコンテクストの値を読み取ります。

これのおかげで、好き勝手にcontextを使うみたいな感じではないかな。

実装

useContextを使ってみる。

import React, { useContext } from 'react';

const ContextA = React.createContext();
const ContextB = React.createContext();

function App() {
  return (
    <ContextA.Provider value={10}>
      <ContextB.Provider value={20}>
        <Preview />
      </ContextB.Provider>
    </ContextA.Provider>
  );
}

function Preview() {
  const valueA = useContext(ContextA);
  const valueB = useContext(ContextB);

  return <p>{valueA} + {valueB}</p>
}

export default App;

参考文献