webpackでバンドルしたTypeScriptのオブジェクトに, ブラウザで実行されるJavaScriptからアクセスする方法

0 前提

$ npm init -y
$ npm install --save-dev typescript ts-loader webpack webpack-cli
$ npx tsc --init

を実行.

次に,

  • ./dist/index.html
  • ./webpack.config.js
  • ./src/index.ts

を後述する通りに準備.

更に,

$ npx webpack

を実行.

最終的なファイル構成は以下の通り.

./dist
./dist/index.html
./dist/index.js
./webpack.config.js
./package-lock.json
./package.json
./tsconfig.json
./src
./src/index.ts

以下, ./distをルートとしてWebサーバを稼働させるものと仮定.

./src/index.ts

export const MSG = "Hello, world!";

MSGが, ブラウザで実行されるJavaScriptからアクセスされるオブジェクトの例.

ブラウザ経由で./dist/index.htmlを読み込むと, 以下のいずれの方法でも, "Hello, world!"というダイアログが表示される.

1 <script src=を用いる方法

./webpack.config.js

const path = require('path');

module.exports = {
  mode: 'development', // "production" | "development" | "none"

  entry: './src/index.ts',

  output: {
    library: {
      type: "umd",
      name: "tmp"
    },
    path: path.join(__dirname, "dist"),
    filename: "index.js",
  },

  module: {
      rules: [{
      test: /\.ts$/,
      use: 'ts-loader'
      }]
  },
};
  output: {
    library: {
      type: "umd",
      name: "tmp"
    },

がポイント.

./dist/index.html

<!DOCTYPE html>

<body>
    <script src="./index.js"></script>
    <script>
        alert(tmp.MSG);
    </script>
</body>

スクリプト中のtmpは, ./webpack.config.jsのoutput.library.nameの値.

2 importを用いる方法

./webpack.config.js

const path = require('path');

module.exports = {
  mode: 'development', // "production" | "development" | "none"

  entry: './src/index.ts',

  experiments: {
    outputModule: true,
  },
  output: {
    library: {
      type: "module",
    },
    path: path.join(__dirname, "dist"),
    filename: "index.js",
  },

  module: {
      rules: [{
      test: /\.ts$/,
      use: 'ts-loader'
      }]
  },
};
  experiments: {
    outputModule: true,
  },
  output: {
    library: {
      type: "module",
    },

がポイント.

dist/index.html

<!DOCTYPE html>

<body>
    <script type="module">
        import * as tmp from "./index.js";
        alert(tmp.MSG);
    </script>
</body>

Macのバッテリー残量を出力するコマンド

シンプルにバッテリー残量のみを出力するコマンドが見当たらなかったので、シェルスクリプトでつくってみました。 単純に、pmset -g battの出力を整形しているだけです。

#!/usr/bin/env bash

getBattLevel () {
    battLevel=`pmset -g batt | grep % | sed -e 's/^.*\t\([0-9]*\)%.*$/\1/'`
    echo ${battLevel}
}

getBattLevel

実行すると、バッテリー残量(%)の数値部分のみを出力します(例えば、バッテリー残量が100%のときに実行すると、100と出力。)。

find -exec {} ;とfind -exec {} +についてのメモ

正確には、以下のように使う。

$ find {$DIR} -exec ${CMD} {} \;
$ find {$DIR} -exec ${CMD} {} +

ここで、${DIR}findの検索対象ディレクトリであり、${CMD}は実行したいコマンドである。 また、\;となっているのは;エスケープするため。

例えば、

$ find .
.
./foo
./bar

であると仮定すると、

$ find . -exec ${CMD} {} \;

は、

$ ${CMD} .
$ ${CMD} ./foo
$ ${CMD} ./bar

と等価であり、

$ find . -exec ${CMD} {} +

は、

$ ${CMD} . ./foo ./bar

と等価である。

【解決済み】HHKB HYBRIDがつながらない

Happy Hacking Keyboard Professional HYBRID Type-S 日本語配列/墨を入手しました。

さっそくWindowsマシンにBluetooth接続しようとしたところ、「デバイスが応答しませんでした。もう一度接続してください。」のメッセージが表示され、一向にペアリングに成功しない...

MacBookで試したところ、すんなりとペアリングに成功。 なので、モノが壊れているわけではないハズ...

で、いろいろやってみた結果、HHKB本体のディップスイッチSW6をONにし、Power Saving Disabledにすることで、ペアリングを成功させることができました。 一旦ペアリングが成功した後は、SW6がOFFでも接続できる模様。

おま環かもしれない...

Windowsファイル共有トラブル・シューティング

先日、WindowsマシンからLinuxマシンで稼働しているSambaへのアクセスにトラブルが発生し、これに対処しました。

以下は、そのことについてのメモです。

確認環境

トラブル1: Windowsマシンの「ネットワーク」にLinuxマシンが表示されない

なお、IPアドレス指定であればLinuxマシン上の共有が表示された。

解決策

Windowsマシンの「コントロールパネル」を開き、

  • プログラム
    • プログラムと機能
      • Windows の機能の有効化または無効化

にて、

  • SMB 1.0/CIFS ファイル共有のサポート
    • SMB 1.0/CIFS クライアント

を有効化する。

解説

現状、SambaはNetBIOS技術を用いた探索にのみ反応する。 一方、Windowsマシンは、上記設定をしないと、NetBIOS技術を用いた探索を行わず、WSD技術を用いた探索のみを行うため、Sambaが稼働しているLinuxマシンが反応しなかったことが原因。

トラブル2: WindowsマシンからLinuxマシン上の共有の認証が通らない

認証ダイアログは開くものの、正しいユーザ名とパスワードを入力しても認証に成功しない。 なお、MacBookからは認証に成功した。

解決策

Windowsマシンの「ローカル セキュリティポリシー」を開き、

  • ローカル ポリシー
    • セキュリティ オプション
      • ネットワーク セキュリティ: LAN Manager 認証レベル

にて、

  • LM と NTLM 応答を送信する

  • NTLMv2 応答のみを送信 (LM と NTLM を拒否する)

に変更する。

解説

Windowsマシンが、Sambaが禁止している認証方式を用いていたことが原因。

即ち、Windowsファイル共有で利用可能な認証方式には以下の方式がある。

  • LM
  • NTLM(「NTLMv1」と呼ばれることもある。)
  • NTLMv2

しかしながら、現状、少なくともデフォルトだと、SambaはLM及びLTLM認証が禁止されているSMB 3.0プロトコルを使用するようである。

TerraMaster Hacking 〜dockerdの自動起動〜

TerraMasterでは、ブラウザからWebページ経由でDockerをインストールすることができるものの、TerraMaster起動時にdockerdが自動起動するように設定することができません。 即ち、TerraMasterを再起動した場合、dockerdを起動するためには、Webページを開いてDockerのアプリ・アイコンをクリックするという面倒な作業が必要となります。

そのため、TerraMasterの起動時にdockerdが自動起動するよう、ターミナルからログインして直接設定を試みたところ、比較的トリッキーな設定が必要でした。

以下は、これについてのメモです。

確認環境

  • TerraMaster F4-210(2GBメモリ)
  • TOS Ver. 4.2.08-2101111540
  • RAID5構成

なお、Dockerはインストール済みであり、sshでログイン可能なことを前提としています。

設定方法

1 適当な場所に以下のシェルスクリプトを作成する

#!/bin/bash

while :
do
    ps -A | grep sshd > /dev/null
    if [[ $? == 0 ]]; then
        break
    fi
    sleep 1
done

PATH=/usr/sbin:/usr/bin:/sbin:/bin:/usr/local/bin:/usr/local/sbin
/etc/init.d/docker start >> /dev/null

exit 0

whileのループは、sshdが起動するまでdockerdの起動を遅延させるためのもの(重要!)。

以下の説明では、/root/startup.shが作成したシェルスクリプトとなります。

2 シェルスクリプトに実行権限を付加する

# chmod a+x /root/startup.sh

3 /etc/rc.localに以下のコマンドを追加する

/root/startup.sh &

&シェルスクリプトをバックグラウンド起動させるためのもの(重要!)。

以上。

おまけ: 失敗の記録

その1: cronの@rebootに/etc/init.d/docker startを登録

TOSのcronは@rebootに対応してませんでした…

その2: /etc/rc.local/etc/init.d/docker startを直接記載する

/etc/rc.localが実行される時点では、dockerdの起動に失敗するようです… 必要なファイルがこの時点ではマウントされていないっぽい。 sshdの起動後であれば問題なさげ(そのためのwhileループ)。

その3: /etc/rc.localに上記シェルスクリプトを直接記載する

/etc/rc.localの実行が終了しないとsshdが起動しないため、無限ループに陥ります…(そのためのバックグラウンド起動)。

SSL証明書の取得 by Let's Encrypt with nginx

nginxを利用してLet's EncryptによりSSL証明書を取得するまで+αの個人的メモです。

環境

関連プログラムのインストール

$ sudo apt update
$ sudo apt install certbot nginx

なお、これによりnginxはデフォルト状態で自動的に起動した。

指定ドメインについてのSSL証明書の取得

$ sudo certbot certonly --webroot -w /var/www/html/ -d ${FQDN}

/var/www/html/はnginxのWebルートに対応するディレクトリのパス。 ${FQDN}SSL証明書を取得したいドメイン。 なお、前提として、外部からのhttp://${FQDN}/*への要求についてnginxが/var/www/html/*を応答できるようにネットワーク(ファイアウォール及びDNSを含む)が設定されていなければならない。 これにより以下のファイルが作成される。

パス 説明
/etc/letsencrypt/live/${FQDN}/fullchain.pem SSL証明書
/etc/letsencrypt/live/${FQDN}/privkey.pem SSL証明書秘密鍵

これにより得られたSSL証明書は、以下のアドレス

  • https://${FQDN}/*

へのアクセスについてセキュリティ警告を発生させないが、例えば以下のアドレス

  • https://www.${FQDN}/*

へのアクセスについてセキュリティ警告を発生させる。

SSL証明書サブドメインをカバーさせる

$ sudo certbot certonly --expand --webroot -w /var/www/html/ -d ${FQDN} -d ${FQDN_SUB}

${FQDN_SUB}SSL証明書を取得したいサブドメイン。 なお、前提として、外部からのhttp://${FQDN}/*及びhttp://${FQDN_SUB}/*への要求についてnginxが/var/www/html/*を応答できるようにネットワークが設定されていなければならない。 これにより、取得したSSL証明書サブドメインをカバーするようになる。

例えば${FQDN_SUB}=www.${FQDN}とおくと、これにより得られた証明書は、以下のアドレス

  • https://${FQDN}/*
  • https://www.${FQDN}/*

へのアクセスについてセキュリティ警告を発生させない。

root以外のユーザからのSSL証明書等へのアクセスの確保

$ sudo chown root:${group} /etc/letsencrypt/{live,archive}/
$ sudo chmod g+rx /etc/letsencrypt/{live,archive}/

${group}は、SSL証明書等を利用したいプログラムの実行ユーザが属するグループ。 /etc/letsencrypt/live/${FQDN}/{fullchain,privkey}.pemは、/etc/letsencrypt/archive/${FQDN}/内のファイルへのシンボリックリンクとなっている。 デフォルトだと、/etc/letsencrypt/{live,archive}/の所有はroot:rootであり、パーミッションは700であるため、root以外のユーザを実行ユーザとするプログラムはSSL証明書等にアクセスできない。

取得したSSL証明書の確認

$ sudo certbot certificates

取得したSSL証明書の更新

$ sudo certbot renew

これにより、取得したSSL証明書の全てが更新されるようである(未確認)が、有効期限の満了が30日以上先のSSL証明書は、以下のようなメッセージが表示されて更新されない模様。

The following certs are not due for renewal yet:
  /etc/letsencrypt/live/${FQDN}/fullchain.pem expires on yyyy-mm-dd (skipped)
No renewals were attempted.