ベスパリブ

プログラミングを主とした日記・備忘録です。ベスパ持ってないです。

Error: Cannot find module 'babel-core'エラーの修正で困った

以下のようなエラーメッセージが表示されてくまった(´・_・`)

$ npm run build-test

> solve-later-again@1.0.0 build-test C:\Users\USER\workspace\solve-later-again\solve-later-again
> webpack-cli -w --mode=development


webpack is watching the files…

Hash: b5aa167f0XXXXXXf2170
Version: webpack 4.41.5
Time: 59ms
Built at: 2020-01-07 6:57:02 AM
     Asset      Size  Chunks             Chunk Names
content.js  4.77 KiB    main  [emitted]  main
Entrypoint main = content.js
[./src/content.js] 3.32 KiB {main} [not cacheable] [built] [failed] [1 error]

ERROR in ./src/content.js
Module build failed (from ./node_modules/babel-loader/lib/index.js):
Error: Cannot find module 'babel-core'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
    at Function.Module._load (internal/modules/cjs/loader.js:562:25)
    at Module.require (internal/modules/cjs/loader.js:692:17)
    at require (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\v8-compile-cache\v8-compile-cache.js:161:20)
    at Object.<anonymous> (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\babel-loader\lib\index.js:3:13)
    at Module._compile (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\v8-compile-cache\v8-compile-cache.js:192:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Module.require (internal/modules/cjs/loader.js:692:17)
    at require (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\v8-compile-cache\v8-compile-cache.js:161:20)
    at loadLoader (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\loader-runner\lib\loadLoader.js:18:17)
    at iteratePitchingLoaders (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\loader-runner\lib\LoaderRunner.js:169:2)
    at runLoaders (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\loader-runner\lib\LoaderRunner.js:365:2)
    at NormalModule.doBuild (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\webpack\lib\NormalModule.js:295:3)
    at NormalModule.build (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\webpack\lib\NormalModule.js:446:15)
    at Compilation.buildModule (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\webpack\lib\Compilation.js:739:10)
    at moduleFactory.create (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\webpack\lib\Compilation.js:1111:12)
    at factory (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\webpack\lib\NormalModuleFactory.js:409:6)
    at hooks.afterResolve.callAsync (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\webpack\lib\NormalModuleFactory.js:155:13)
    at AsyncSeriesWaterfallHook.eval [as callAsync] (eval at create (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\tapable\lib\HookCodeFactory.js:33:10), <anonymous>:6:1) 
    at AsyncSeriesWaterfallHook.lazyCompileHook (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\tapable\lib\Hook.js:154:20)
    at resolver (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\webpack\lib\NormalModuleFactory.js:138:29)
    at process.nextTick (C:\Users\USER\workspace\solve-later-again\solve-later-again\node_modules\webpack\lib\NormalModuleFactory.js:346:9)
    at process._tickCallback (internal/process/next_tick.js:61:11)

エラーメッセージでググるCannot find module 'babel-core' · Issue #124 · babel/gulp-babel · GitHub というドンピシャな記事がヒットするのですが、この記事に書いてあるようにnpm install --save-dev @babel/core @babel/preset-envをしてもエラーは解消しませんでした(というか元々@babel/core と @babel/preset-env を使っててアップデートしたけどダメだった)。

しょうがないので、すべてのパッケージをアップデートしてみることにしました。

結論を言うと、babel-loaderをアップデートしたら直りました。

パッケージのアップデート方法

npmパッケージのアップデートは依存関係を調べながら更新できるnpm-check-updatesが便利らしい1ので、それを使います。

# npm-check-updatesをグローバルインストールする
$ npm install -g npm-check-updates
C:\Users\USER\AppData\Roaming\npm\npm-check-updates -> C:\Users\USER\AppData\Roaming\npm\node_modules\npm-check-updates\bin\npm-check-updates
C:\Users\USER\AppData\Roaming\npm\ncu -> C:\Users\USER\AppData\Roaming\npm\node_modules\npm-check-updates\bin\ncu
+ npm-check-updates@4.0.1
added 259 packages from 95 contributors in 7.414s

# npm-check-updatesの実行
$ ncu
Checking C:\Users\USER\workspace\solve-later-again\solve-later-again\package.json
[====================] 5/5 100%

 babel-loader  ^7.1.5  →  ^8.0.6

Run ncu -u to upgrade package.json

$ ncu -u
Upgrading C:\Users\USER\workspace\solve-later-again\solve-later-again\package.json
[====================] 5/5 100%

 babel-loader  ^7.1.5  →  ^8.0.6

Run npm install to install new versions.


$ npm install
npm WARN solve-later-again@1.0.0 No repository field.
npm WARN optional SKIPPING OPTIONAL DEPENDENCY: fsevents@1.2.11 (node_modules\fsevents):
npm WARN notsup SKIPPING OPTIONAL DEPENDENCY: Unsupported platform for fsevents@1.2.11: wanted {"os":"darwin","arch":"any"} (current: {"os":"win32","arch":"x64"})

removed 9 packages, updated 1 package and audited 6710 packages in 2.216s
found 0 vulnerabilities

このあとビルドしたら直りました(^-^≡^-^)

参考URL

Surface Go ブルースクリーン

重要

検索すると色々なサイトが出てくるが、とにかく最新のMicrosoftの公式サポートのページを見ること。

手順

Surface Go 故障 カスタマーサポート」などで検索し、チャットで問題の現状を書き込むと、該当ページに飛ばしてくれるはずです。

Surface の USB 回復ドライブの作成と使用

以下に書いてあることはやったことの要約です。公式サポートを読んで進めたほうがよいです。

  1. 正常に稼働する別のPCで、Surface の回復イメージをダウンロード
  2. 正常に稼働する別のPCで、回復メディアドライブツールを起動。USBメモリ(128GB)に回復ドライブを作成する(「システムファイルを回復ドライブにバックアップします」のチェックボックスは外すこと)。
  3. その後回復イメージをダウンロードする。ダウンロードしたファイルを開き、回復ドライブのUSBメモリにコピーする。上書きするか聞かれたら上書き保存する。
  4. 回復ドライブ(USBメモリ)をSurface Goに挿し、Surface Goを起動する。もし「Recovery Your PC/Device needs to be repaired」と表示されたら、USBメモリの回復ドライブを認識する順序を変更する必要があるので、Windowsキーを押し、UEFI画面を開く。
  5. Boot configuratin で、「USB Storage」の優先度を一番上にする。詳しくは「公式のUSB デバイスから Surface を起動する」を参照
  6. 再起動する。
  7. すると、画面が表示されるので、表示される画面に従ってリカバリする。

Office製品のアクティベーションは?

2019年12月現在、日本向けSurface GoではOfficeのアクティベーションはプロダクトキーではなく、Microsoftアカウントに紐付けられていました。

とりあえずOfficeを起動すると「アクティベーション方法」みたいなリンクを表示してくれるので、そのリンクを踏んだ先に書いてあるとおりにすれば再アクティベーションが可能なはず。リンクを踏んだ先では、「プロダクトキーでアクティベーションしないでください。Microsoftアカウントを使ってください」という旨が書いてあったので私はそうしました。

TypeScriptの開発環境構築メモ

TypeScriptのインストール

TypeScriptのインストール方法はグローバルインストールとローカルインストールの2種類あります。

グローバルインストール方法は以下です。

$ npm install -g typescript

環境を汚したくない場合はローカルインストールをします。node_modulesが作成されその中にインストールされます。こっちだとpackage.jsonpackage-lock.jsonにTypeScript情報が追記されて、移植性が高いのでおすすめ。

$ npm install --save typescript
# または
$ npm install --save-dev typescript

--saveと--save-devの違いはnpmの--save, --save-dev, --save-optionalの違い - how to code something を参照。今回私はChrome拡張を作るつもりなので--save-devでインストールします。

ローカルインストールの場合、tscコマンドを相対パスで指定する必要があります。毎回それだと面倒くさいので、package.json(package-lock.jsonではない)のscriptsフィールドにショートカットを記述します。

{
  "name": "sample",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "tsc": "tsc"
  },
  ...
}

こうすることで、npm runコマンドでローカルインストールしたnode_modules内のtscを実行できるようになります。

$ tsc  # グローバルインストールの場合
$ npm run tsc  # ローカルインストールの場合

参考URL

tsconfig.jsonの作成

次にtsconfig.jsonの雛形を作成します。これはTypeScriptからJavaScriptにトランスパイルする際の設定ファイルです。

# グローバルインストールの場合
$ tsc --init        

# ローカルインストールの場合
$ ./node_modules/.bin/tsc --init

# npm run tsc はオプション引数を渡すことができないので、以下だとエラーが発生する
$ npm run tsc --init  

tsconfig.jsonの代表的なプロパティは以下のような感じです。

compilerOptions.target

生成するJavaScriptECMAScriptバージョン。

compilerOptions.module

モジュールの形式。

compilerOptions.strict

厳密な型変換をするかどうか(暗黙的な型変換を許さないかどうか)。TrueでOK

compilerOptions.esModuleInterop

CommonJS形式で書かれた外部ライブラリのモジュールを妥当に扱えるようにするらしいです。よくわからないからそのままで。

compilerOptions.outDir

tscをしてコンパイルしたとき、出力ファイルはtsconfig.jsと同じ場所に出力されます。別フォルダに出力したいときはこのプロパティで指定します。

dstフォルダに出力したいときは以下のようにします。

{
  "compilerOptions": {
    "outDir": "dst",                        /* Redirect output structure to the directory. */
  ...
}

Include

tscコマンドでコンパイルするファイルをフォルダで指定します。

srcフォルダ内のファイルを対象としたいときは以下のようにします。

{
  "compilerOptions": {
  ...
  },
  "include": [
    "src/**/*"
  ]
}

allowJsとcheckJs

tscコンパイル対象にJavaScriptファイルを含めたいときには、これらの項目を設定します。既存のJavaScriptファイルをTypeScript内でimportしたいときはこの設定が必要です。

{
  "compilerOptions": {
    ...,
    "allowJs": true,
    "checkJs": true
  }
}

まとめ

tsconfig.jsonは、例えば私の場合は以下のようになりました。

{
  "compilerOptions": {
    "target": "es5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "commonjs",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "allowJs": true,                       /* Allow javascript files to be compiled. */
    "checkJs": true,
    "outDir": "dst",                        /* Redirect output structure to the directory. */
    "strict": true,                           /* Enable all strict type-checking options. */
    "esModuleInterop": true                   /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
  },
  "include": [
    "src/**/*"
  ]
}

ビルドツールのインストール

実際のアプリ開発では直接tscコマンドを打つことはなく、ビルドツールと連携して使うことが多いようです。

私の場合はwebpackを使いたいのでそれに関するものをインストールします。

webpackのインストール

webpackはTypeScriptの自動コンパイル、複数のソースコードの結合、ソースコード更新時の自動リロードなどをしてくれます。一部tscと機能が被っていますね。

$ npm install --save-dev typescript ts-loader webpack webpack-cli webpack-dev-server webpack-merge

ざっくりとですが、各モジュールについて私の理解で書いておきます。

  • typescript
    • TypeScriptファイル(.ts)をコンパイルするために必要。
  • ts-loader
    • よくわからないけど、TypeScriptと連携するために必要なwebpack用のloader。
  • webpack
    • webpackを使って.tsファイルをコンパイルするために必要。
  • webpack-cli
    • 開発中に、ファイルを保存したらコンパイルも自動でされるみたいな便利なことをするために必要。
  • webpack-dev-server
    • 開発用WEBサーバ。
  • webpack-merge
    • webpack.config.jsを、開発用と本番用にファイルを分割するために必要。

ts-loaderはnode_modules内にtypescriptがあることを前提としているので、typescriptをローカルインストールする必要があるらしいです。

webpack.config.js

webpackの設定ファイルです。設定方法は参考URLのTypeScriptチュートリアル① -環境構築編- - Qiitaが詳しいのでそちらを参照。

const path = require('path');
module.exports = {
    entry: {
        content_scripts: './src/content_scripts.ts'
    },  
    output: {
        path: path.join(__dirname,'dst'),
        filename: '[name].js'  // [name]は、entryのプロパティ名(content_scripts)
    },
    optimization: {
        minimize: true
    },
    resolve: {
        extensions:['.ts','.js']
    },
    devServer: {
        contentBase: path.join(__dirname,'dst')
    },
    module: {
        rules: [
            {
                test:/\.ts$/,
                use: {
                    loader:'ts-loader'
                }
            }
        ]
    }
}

出力フォルダの指定などがtsconfig.jsonと被ってますね。webpackを通じてコンパイルするときはwebpack.config.jsの設定でされるのできちんと設定しておきます。

webpack.config.jsを開発用と本番用にファイルを分ける

webpackで開発用/本番用の設定を分ける - Qiitaが詳しいのでそちらを参照。

例えば、開発用は出力ファイルを圧縮せずに、本番用は出力ファイルを圧縮する。といった切り替えをしたいです。このようにしたいとき、公式の推奨によるとwebpack.config.jsを以下のようにファイル分割します。

  • webpack.common.js
    • 共通設定。開発用と本番用の両方に適用したい設定を記述します。
  • webpack.dev.js
    • 開発用設定
  • webpack.prod.js
    • 本番用設定

例えば私は以下のようになりました。

webpack.common.js

const path = require('path');
module.exports = {
    entry: {  // ビルドの起点となるファイルの指定
        content_scripts: './src/content_scripts.ts'
    },
    output: {  // ビルド結果の出力場所
        path: path.join(__dirname,'dst'),
        filename: '[name].js'  // [name]は、entryのプロパティ名(content_scripts)
    },    
    resolve: {  // モジュールとして扱いたいファイルの拡張子を指定する
        extensions:['.ts','.js']
    },
    devServer: {
        // webpack-dev-serverの公開フォルダ
        contentBase: path.join(__dirname,'dst')
    },
    module: {
        rules: [
            {
                // 拡張子が.tsで終わるファイルに対して、TypeScriptコンパイラを適用する
                test:/\.ts$/,
                use: {
                    loader:'ts-loader'
                }
            }
        ]
    }
}

webpack.dev.js

// webpack-merge ver.5.0.3以降は { merge } = ... という書き方になる
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js') // 汎用設定をインポート

// common設定とマージする
module.exports = merge(common, {
    mode: 'development', // 開発モード
    devtool: 'inline-source-map', // 開発用ソースマップ
    optimization: {
        minimize: false  // 出力JSファイルを圧縮しない
    }
})

webpack.prod.js

// webpack-merge ver.5.0.3以降は { merge } = ... という書き方になる
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js') // 汎用設定をインポート

// common設定とマージする
module.exports = merge(common, {
    mode: 'production', // 本番モード
    optimization: {
        minimize: true  // 出力JSファイルを圧縮する
    }
})

package.jsonを編集してwebpackのコマンドを簡単に使えるようにする

package.jsonのscriptsフィールドに、以下のプロパティを追加します。

  "scripts": {
    "tsc": "tsc",
    "build": "webpack --config webpack.prod.js",
    "build-dev": "webpack-cli -w --config webpack.dev.js",
    "server": "webpack-dev-server --config webpack.dev.js"
  },

これにより、

  • npm run buildで、webpackをProduction(本番環境)モードで起動して、ビルドする
    • .tsファイルを本番用にビルドする用のコマンド
  • npm run build-devで、webpack-cliをDevelopment(開発)モードかつwatchモード(ファイルを保存すると自動ビルドされる)で起動する
    • 普段の開発中はこちらを使う
  • npm run serverで、webpack-dev-serverを開発モードで起動する
    • webpack-dev-serverは、開発用WEBサーバーを起動するコマンド。localhost:8080にアクセスできる

ができるようになりました。webpack-dev-serverはビルド処理もしてくれるため、基本的にnpm run serverだけ使っておけば問題ないらしいですが、webpack-dev-serverは、ファイルを変更したときはdstフォルダに出力ファイルは更新されず、メモリ上に保存されるようです。

私の場合はChrome拡張を作りたかったので、Chrome拡張は出力ファイルをChromeにアップロードする必要があるので、出力ファイルが更新されないと困ります。なので代わりにwebpack-cliを使い、npm run build-devを中心に使って開発を進めることになります。

参考URL

@typesのインストール

@typesは型定義ファイルで、例えばChrome拡張を作るときは@types/chromeをインストールしておかないと、chrome.runtime.onMessage.addListenerなどをコードに書いてコンパイルしたらTS2304: Cannot find name 'chrome'.みたいなコンパイルエラーが出ます。なのでプロジェクトに必要な型定義ファイルを適宜インストールする必要があります。

例えばChrome拡張の場合は、@types/chromeをインストールします。

$ npm install --save-dev @types/chrome

Reactのインストール

今回、Chrome拡張で設定画面を作りたいのですが、せっかくなので練習も兼ねてReactで作ることにしました。

$ npm install --save-dev react react-dom
$ npm install --save-dev @types/react-dom @types/react-dom

「実践TypeScript」という本にはparcelを使うと便利とありますが、私の場合はwebpackを使用していますので、今回はparcelは不要なのでインストールしません。parcelは設定ファイルなしで即React環境を構築できるのがメリットな反面、複雑な設定ができないというデメリットがあるようです。

Reactを使う場合、.tsxファイルを使いますので、これのビルドを許可するように設定ファイルを書き換えます。

tsconfig.json

  "compilerOptions": {
    "target": "ES5",                          /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019' or 'ESNEXT'. */
    "module": "es2015",                     /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', or 'ESNext'. */
    "jsx": "react",                     /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
   ...

jsxを'react'にします。また、必須ではないですがmoduleをes2015にしました。理由は 最新版TypeScript+webpack 5の環境構築まとめ(React, Vue.js, Three.jsのサンプル付き) - ICS MEDIA の「TypeScriptの設定ファイル: tsconfig.json」の章を読んでそうしました。

webpack.common.js

    entry: {
        content_scripts: './src/content_scripts.ts',
        background: './src/background.ts',
        index: './src/index.ts',
        app:'./src/react/app.tsx'  // ★これを追加
    },
    output: {
        // モジュールバンドルを行った結果を出力する場所やファイル名の指定
        // "__dirname"はこのファイルが存在するディレクトリを表すnode.jsで定義済みの定数
        path: path.join(__dirname,'dst/js'),
        filename: '[name].js'  // [name]は、entryのプロパティ名(content_scripts)
    },
    // モジュールとして扱いたいファイルの拡張子を指定する
    // 例えば「import Foo from './foo'」という記述に対して"foo.ts"という名前のファイルをモジュールとして探す
    // デフォルトは['.js', '.json']
    resolve: {
        extensions:['.ts','.tsx', '.js']  // ★tsxを追加
    },
    devServer: {
        // webpack-dev-serverの公開フォルダ
        contentBase: path.join(__dirname,'dst')
    },
    // モジュールに適用するルールの設定(ここではローダーの設定を行う事が多い)
    module: {
        rules: [
            {
                // 拡張子が.tsで終わるファイルに対して、TypeScriptコンパイラを適用する
                test:/\.(ts|tsx)$/,  // ★tsxを追加
                use: {
                    loader:'ts-loader'
                }
            }
        ]
    }

フォルダ構成は次のようになっています(一部省略しています)。

root/
├dst/
│  ├js/
│  │  └ app.js
│  └ index.html
├src/
│  └ react/
│      └ app.tsx
├package.json
├tsconfig.json
├ webpack.common.js

ReactでDOMを構築するためのファイルはsrc/react/app.tsxです。これをnpm run build-test等でコンパイルすると、dst/js/app.jsが作成されます。index.htmldstフォルダ側に作成し、app.jsを読み込むようにします。

index.html

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>ReactTest</title>
  </head>
  <body>
    <div id="app"></div>
    あああああああああああああああああああああああああああ
    <!-- Load our React component. -->
    <script src="/js/app.js"></script>
  </body>
</html>

app.tsx

import * as React from 'react';
import { render } from 'react-dom';

render(<div>Hello World!!!!!</div>, document.getElementById('app'));

コンパイル後にWebサーバーを立ち上げindex.htmlにアクセスし、「Hello World!!!!!」が表示されていたら成功です。

参考URL

index.htmlをsrcフォルダに入れたい

「index.htmlファイルがdstにあってそれを直接編集するのおかしくねぇ?srcにあるべきじゃん」と思っていて、そういう方法がないか調べました。

React & TypeScriptのプロジェクト作成 - TypeScript Deep Dive 日本語版にその方法が載っていたのでそれを踏襲します。

clean-webpack-pluginhtml-wabpack-pluginを使うので、それらをインストールします。

$ npm install --save-dev clean-webpack-plugin html-webpack-plugin

その後、webpack.common.js(webpack.config.js)を以下のように編集します(編集箇所を★でマークしています)。

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');  // ★追加
const HtmlWebpackPlugin = require('html-webpack-plugin');  // ★追加

module.exports = {
    // モジュールバンドルを行う起点となるファイルの指定
    // 指定できる値としては、ファイル名の文字列や、それを並べた配列やオブジェクト
    // 下記はオブジェクトとして指定した例
    entry: {
        content_scripts: './src/content_scripts.ts',
        background: './src/background.ts',
        index: './src/index.ts',
        app:'./src/react/app.tsx'
    },
    // ★pluginsプロパティを追加
    plugins: [
        new CleanWebpackPlugin({
            cleanAfterEveryBuildPatterns: ['dst']
        }),
        new HtmlWebpackPlugin({
            template: 'src/templates/index.html'
        }),
    ],
    output: {
        // モジュールバンドルを行った結果を出力する場所やファイル名の指定
        // "__dirname"はこのファイルが存在するディレクトリを表すnode.jsで定義済みの定数
        path: path.join(__dirname,'dst'),  // ★出力フォルダをdstに修正
        filename: 'js/[name].js'  // ★jsファイルの出力は 'js/[name].js'に修正
    },
    // モジュールとして扱いたいファイルの拡張子を指定する
    // 例えば「import Foo from './foo'」という記述に対して"foo.ts"という名前のファイルをモジュールとして探す
    // デフォルトは['.js', '.json']
    resolve: {
        extensions:['.ts','.tsx', '.js']
    },
    devServer: {
        // webpack-dev-serverの公開フォルダ
        contentBase: path.join(__dirname,'dst')
    },
    // モジュールに適用するルールの設定(ここではローダーの設定を行う事が多い)
    module: {
        rules: [
            {
                // 拡張子が.tsで終わるファイルに対して、TypeScriptコンパイラを適用する
                test:/\.(ts|tsx)$/,
                use: {
                    loader:'ts-loader'
                }
            }
        ]
    }
}

フォルダ構成は以下のようになっています(一部省略)。

root/
├dst/
│  └js/
│     └ app.js
├src/
│  ├ react/
│  │   └ app.tsx
│  └ templates/
│        └ index.html
├package.json
├tsconfig.json
├ webpack.common.js

これでnpm run build-test等してビルドすると、src/templates/index.htmlをビルドしたものがdst/直下に作成されます。

これで、ソースファイルはsrcフォルダにまとめることができました。

その他の参考

編集履歴

日時 編集内容
2022/1/9 webpack-mergeをver.5.0.3以降の書き方に修正
2020/3/19 tsconfig.jsonの作成方法を修正
2020/1/6 React公式の参考URLを追加
2019/12/31 「index.htmlをsrcフォルダに入れたい」の項目を追加
2019/12/29 Reactのインストールの項目を追加
2019/12/15 16:00頃 @typesに関する記述を追加
2019/12/15 04:41頃 初版

gencache.EnsureModuleのメモ

gencache.EnsureModule()周りを色々調べたついでに備忘録を残します。

EnsureModule()を呼び出す理由

そもそもなんでgencache.EnsureModule()を呼び出さないといけないかというと、Dispatchする前にearly binding(事前バインディング)したいからなのです。

詳細は以下を参考にします。

Dispatch()でこれまで使用したことのないCOMオブジェクトを作成しようとすると、Pythonはオブジェクトが何を利用できるかわからないのでエラーが発生します。その場合、EnsureDispatch()を使うことで事前バインディングになるので、Pythonはオブジェクトが何を利用できるかわかるようになります。

win32.dynamic.Dispatch()というのもあり、こちらは常にlate binding(遅延バインディング)になるようです。

win32com.client.Dispatch()で動かない場合はgencache.EnsureModule()を使うことで、正しくキャッシュモジュールを生成することができます。

EnsureModule()の引数

上記の1個目のサイトを読むと、win32comの場所を調べると良さそうです。

>>> import win32com
>>> win32com.__file__ 
'C:\\Users\\XXXX\\AppData\\Local\\Continuum\\anaconda3\\envs\\projectX\\lib\\site-packages\\win32com\\__init__.py'
>>>

C:\Users\XXXX\AppData\Local\Continuum\anaconda3\envs\projectX\Lib\site-packages\win32com\client\gencache.pyがあったので、EnsureModule()の実装を見てみます。

def EnsureModule(typelibCLSID, lcid, major, minor, progressInstance = None, bValidateFile=not is_readonly, bForDemand = bForDemandDefault, bBuildHidden = 1):
    """Ensure Python support is loaded for a type library, generating if necessary.
  
  Given the IID, LCID and version information for a type library, check and if
  necessary (re)generate, then import the necessary support files. If we regenerate the file, there
  is no way to totally snuff out all instances of the old module in Python, and thus we will regenerate the file more than necessary,
  unless makepy/genpy is modified accordingly.
  
  
  Returns the Python module.  No exceptions are caught during the generate process.

  Params
  typelibCLSID -- IID of the type library.
  major -- Integer major version.
  minor -- Integer minor version
  lcid -- Integer LCID for the library.
  progressInstance -- Instance to use as progress indicator, or None to
                      use the GUI progress bar.
  bValidateFile -- Whether or not to perform cache validation or not
  bForDemand -- Should a complete generation happen now, or on demand?
  bBuildHidden -- Should hidden members/attributes etc be generated?
  """

lcidはロケールIDだとすると、gencache.EnsureModule('{D98A091D-3A0F-4C3E-B36E-61F62068D488}', 0, 1, 0)の引数は左から順に、

  • クラスID
  • ロケールID
  • メジャーバージョン番号
  • マイナーバージョン番号

ということだと思います。

また、適当にフォルダを適当に漁るとmakepy.pyを見つけることができます。

C:\Users\XXXX\AppData\Local\Continuum\anaconda3\envs\projectX\Lib\site-packages\win32com\client

のmakepy.pyの104-106行目になんか書いてあります。

       print(" >>> # Use these commands in Python code to auto generate .py support")
        print(" >>> from win32com.client import gencache")
        print(" >>> gencache.EnsureModule('%s', %s, %s, %s)" % (tlbSpec.clsid, tlbSpec.lcid, tlbSpec.major, tlbSpec.minor))

tlbSpecはおそらくキャッシュのTLB(Translation Lookaside Buffer)のことだと思います。なのでおそらく、クラスID等でアプリケーションを指定して、TLBでそのアプリケーションにメモリが割り当てられているといったことをしているのでしょう。

Matrix(行列)用語まとめ

Matrix

  • 行列のこと。
  • 複数形はmatrices

Pre-Multiply, Pre-Multiplication


A = 
\begin{pmatrix} 
a & b & c \\
d & e & f \\
g & h & i
\end{pmatrix} 
, B = 
\begin{pmatrix} 
1 & 0 & 0 \\
0 & 0 & 0 \\
0 & 0 & 0
\end{pmatrix} 
のとき、

\\
BA = 
\begin{pmatrix} 
a & b & c \\
0 & 0 & 0 \\
0 & 0 & 0
\end{pmatrix} 

Post-Multiply, Post-Multiplication


A = 
\begin{pmatrix} 
a & b & c \\
d & e & f \\
g & h & i
\end{pmatrix} 
, B = 
\begin{pmatrix} 
1 & 0 & 0 \\
0 & 0 & 0 \\
0 & 0 & 0
\end{pmatrix} 
のとき、

\\
AB = 
\begin{pmatrix} 
a & 0 & 0 \\
d & 0 & 0 \\
g & 0 & 0
\end{pmatrix} 

Square Matrix

  • 正方行列のこと。

Transposition Matrix


A = 
\begin{pmatrix} 
1 & 2 & 3 \\
4 & 5 & 6 \\
7 & 8 & 9
\end{pmatrix} 
, B = 
\begin{pmatrix} 
a & b & c \\
d & e & f 
\end{pmatrix} 

\\

A^{T} = 
\begin{pmatrix}
1 & 4 & 7 \\
2 & 5 & 8 \\
3 & 6 & 9
\end{pmatrix} 
, B^{T} = 
\begin{pmatrix} 
a & d \\
b & e \\
c & f
\end{pmatrix} 

Translation Matrix

  • 平行移動行列のこと。
    • 平行移動は、並進とも言われる。

Rotation Matrix

  • 回転行列のこと。

Partitioned Matrix, Block Matrix

Mapping

Reflection

  • 鏡像変換、鏡映変換
  • ある軸を鏡とみなして、鏡に映るように変換する

Row Reflection


\begin{pmatrix} 
0 & 0 & 1 \\
0 & 1 & 0 \\
1 & 0 & 0
\end{pmatrix} 
\begin{pmatrix} 
a & b & c \\
d & e & f \\
g & h & i
\end{pmatrix} 
=
\begin{pmatrix} 
g & h & i \\
d & e & f \\
a & b & c
\end{pmatrix} 

Column Reflection


\begin{pmatrix} 
a & b & c \\
d & e & f \\
g & h & i
\end{pmatrix} 
\begin{pmatrix} 
0 & 0 & 1 \\
0 & 1 & 0 \\
1 & 0 & 0
\end{pmatrix} 
=
\begin{pmatrix} 
c & b & a \\
f & e & d \\
i & h & g
\end{pmatrix} 

Identity

  • 単位行列のこと。
    • 単位行列はEで覚えてたが、Iとも書くようです。
    • EA = A のとき、EはIdentity

3 by 4 matrix

  • 3x4行列。
  • 3行4列の行列。

Determinant

Matrix Product

  • 行列の積
  • "product of matrices A and B"
    • AとBの積
    • これだけだと、ABかBAかはわからない。文脈で判断する。

Inner Product

Outer Product

Transposing

  • 転置のこと。

参考

編集履歴

日時 編集内容
2019/12/16 参考URLを追加
2019/12/05 初版

リモートデスクトップの上のバーの消し方と切断方法

上のバー、ハイパー邪魔。

消し方

  1. リモートデスクトップの接続画面
  2. オプションの表示
  3. 「画面」メニュー
  4. 「全画面表示の使用時に接続バーを表示する」のチェックを外す

f:id:takeg:20191204090438p:plain

切断方法

  1. スタートボタンを右クリック
  2. 「シャットダウンまたはサインアウト」
  3. 「切断」を選択

f:id:takeg:20191204090445p:plain

小数点以下の不要な0を除去したい(Python)

何がやりたいかと端的に言うと、

  • 30.100 => 30.1
  • 30.000 => 30

のようにしたい。

Decimalモジュールを使う

小数点といえばDecimalなので、Decimalモジュールを探したらそれっぽいDecimal.normalizeがありました。

数値を正規化 (normalize) して、右端に連続しているゼロを除去し、 Decimal('0') と同じ結果はすべて Decimal('0e0') に変換します。等価クラスの属性から基準表現を生成する際に用います。たとえば、 Decimal('32.100') と Decimal('0.321000e+2') の正規化は、いずれも同じ値 Decimal('32.1') になります。

これは良さそう。早速使ってみます。

from decimal import Decimal
s = "30.0"
a = Decimal.normalize(Decimal(s))
print(a)
# 3E+1

うーん。指数表現になってしまった。

他に使えそうなものを探すと、Context.normalizeがありました。こっちを使ってみましょう。

from decimal import Decimal, Context

s = "30.0"

context = Context()
a = context.normalize(Decimal(s))
print(a)
#3E+1

変わらないですね。指数表現じゃなくしてほしいんですが。

色々漁ってると、Decimal FAQにドンピシャなQAがありました。

Q. ある種の十進数値はいつも指数表記で表示されます。指数表記以外の表示にする方法はありますか?

A. 値によっては、指数表記だけが有効桁数を表せる表記法なのです。たとえば、 5.0E+3 を 5000 と表してしまうと、値は変わりませんが元々の2桁という有効数字が反映されません。

もしアプリケーションが有効数字の追跡を等閑視するならば、指数部や末尾のゼロを取り除き、有効数字を忘れ、しかし値を変えずにおくことは容易です:

>>> def remove_exponent(d):
...     return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
>>> remove_exponent(Decimal('5E+3'))
Decimal('5000')

なるほど。

結論

というわけで、数値(float or int)から正規化した文字列(str)を返す関数は以下のようになります。

from decimal import Decimal, Context


def decimal_normalize(f):
    """数値fの小数点以下を正規化し、文字列で返す"""
    def _remove_exponent(d):
        return d.quantize(Decimal(1)) if d == d.to_integral() else d.normalize()
    a = Decimal.normalize(Decimal(str(f)))
    b = _remove_exponent(a)
    return str(b)

print(decimal_normalize(30.0))
# 30
print(decimal_normalize(30))
# 30
print(decimal_normalize(30.0001000))
# 30.0001
print(decimal_normalize(0.0))
# 0
print(decimal_normalize(0))
# 0
print(decimal_normalize(-5.0))
# -5

Decimal(x)するときに、xはstr型にする必要はなくてfloat型のままでもいけますが、私はstr型に変換するようにしています。なんか挙動の差があって、str型に変換したほうが安定していたイメージがあるので(うろおぼえ)。

Decimalモジュールを使わない

Decimalモジュールを探す前に書いていたコード。Decimalを使いたくないときはこっちでもまあ。

def decimal_normalize(f):
    text = str(f)
    while True:
        if ("." in text and text[-1] == "0") or (text[-1] == "."):
            text = text[:-1]
            continue
        break
    return text

print(decimal_normalize(30.0))
# 30
print(decimal_normalize(30))
# 30
print(decimal_normalize(30.0001000))
# 30.0001
print(decimal_normalize(0.0))
# 0
print(decimal_normalize(0))
# 0
print(decimal_normalize(-5.0))
# -5