TypeScriptのインストール
TypeScriptのインストール方法はグローバルインストールとローカルインストールの2種類あります。
グローバルインストール方法は以下です。
$ npm install -g typescript
環境を汚したくない場合はローカルインストールをします。node_modules
が作成されその中にインストールされます。こっちだとpackage.json
やpackage-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 --init
tsconfig.jsonの代表的なプロパティは以下のような感じです。
compilerOptions.target
生成するJavaScriptのECMAScriptバージョン。
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
- 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'
},
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'
},
resolve: {
extensions:['.ts','.js']
},
devServer: {
contentBase: path.join(__dirname,'dst')
},
module: {
rules: [
{
test:/\.ts$/,
use: {
loader:'ts-loader'
}
}
]
}
}
webpack.dev.js
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
optimization: {
minimize: false
}
})
webpack.prod.js
const { merge } = require('webpack-merge')
const common = require('./webpack.common.js')
module.exports = merge(common, {
mode: 'production',
optimization: {
minimize: true
}
})
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(本番環境)モードで起動して、ビルドする
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: {
path: path.join(__dirname,'dst/js'),
filename: '[name].js'
},
resolve: {
extensions:['.ts','.tsx', '.js']
},
devServer: {
contentBase: path.join(__dirname,'dst')
},
module: {
rules: [
{
test:/\.(ts|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.html
はdst
フォルダ側に作成し、app.js
を読み込むようにします。
index.html
<html lang="ja">
<head>
<meta charset="utf-8">
<title>ReactTest</title>
</head>
<body>
<div id="app"></div>
あああああああああああああああああああああああああああ
<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-plugin
とhtml-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: [
new CleanWebpackPlugin({
cleanAfterEveryBuildPatterns: ['dst']
}),
new HtmlWebpackPlugin({
template: 'src/templates/index.html'
}),
],
output: {
path: path.join(__dirname,'dst'),
filename: 'js/[name].js'
},
resolve: {
extensions:['.ts','.tsx', '.js']
},
devServer: {
contentBase: path.join(__dirname,'dst')
},
module: {
rules: [
{
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頃 |
初版 |