typescriptのコードをvscodeでデバッグしつつコンパイルしてサーバに転送する雛形
いつもの手順をメモ。windows環境。gulpのところが環境依存強くて、rm -rf
コマンド投げてるので注意。gulpのところはもっといい方法があるはずなので指摘歓迎。
最終的に以下のファイルが設置される
/.vscode/launch.json
/.vscode/settings.json
/.vscode/tasks.json
/.gitignore
/gulpConfig.json
/gulpfile.js
/package.json
/package-lock.json
/pm2.json
/tsconfig.json
npm初期化
gulpはバージョン4系を使うのでnextを指定。お好みでexpressを指定したり。
$ npm init -y
$ npm install --save dateformat fs-extra node-fetch
$ npm install --save-dev @types/dateformat @types/fs-extra @types/node @types/node-fetch typescript gulp@next gulp-ssh ssh-config
$ mkdir ./src
$ mkdir ./.vscode
typescript設定
かなり厳しい。未使用の変数や引数が全部エラーになるので。
参考サイト
- Compiler Options · TypeScript
- tsconfig.json で指定できる全 compilerOptions をまとめた (TypeScript v2.5 版) - Corredor
{
"compilerOptions": {
// コンパイルバージョン。これを古い値にすると、xxというメソッドは無い!というエラーが出るようになる
"target": "es2017",
// nodejsが標準対応しているcommonjsを指定
"module": "commonjs",
"sourceMap": true,
"outDir": "./out",
"rootDir": "./src",
// 文字コード指定。念の為。
"charset": "utf8",
"alwaysStrict": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
// d.tsファイルも作る事を指定する
"declaration": true,
// trueでBOMを削除する。念の為
"emitBOM": true,
// inlineSourceMapはchrome68で非対応なので無し。この項目を指定する時は"sourceMap"の指定を削除する必要がある。
//"inlineSourceMap": true
// ソースマップにソースコード自体を入れる。
"inlineSources": true,
"newLine": "LF",
"noEmitOnError": true,
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitUseStrict": false,
// trueで未使用のローカル変数をエラーにする。過剰かも
"noUnusedLocals": false,
// trueで未使用の関数の引数をエラーにする。過剰かも
"noUnusedParameters": true,
// tureでコンパイルにかかった時間やメモリ使用量を表示する。邪魔かも
"diagnostics": true,
"strictNullChecks": true,
}
}
vscode設定
typescriptでビルドしてローカルで実行する起動と、gulpを使ってサーバにデプロイする起動の二種類。
{
// IntelliSense を使用して利用可能な属性を学べます。
// 既存の属性の説明をホバーして表示します。
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"type": "node",
"request": "launch",
"name": "プログラムの起動",
"program": "${workspaceFolder}/out/index.js",
"preLaunchTask": "typescriptをビルド",
"outFiles": [
"${workspaceFolder}/out/**/*.js"
]
},
{
"type": "node",
"request": "launch",
"name": "gulp-deploy",
"program": "${workspaceFolder}/node_modules/gulp/bin/gulp.js",
"args": [
"deploy"
]
}
]
}
{
// See https://go.microsoft.com/fwlink/?LinkId=733558
// for the documentation about the tasks.json format
"version": "2.0.0",
"tasks": [
{
"label": "typescriptをビルド",
"type": "typescript",
"tsconfig": "tsconfig.json",
"problemMatcher": [
"$tsc"
]
}
]
}
ウィンドウのタイトルをカスタマイズするのと、typescriptコンパイラをプロジェクトのそれに指定。
{
"window.title": "プロジェクト名 - ${activeEditorMedium}${separator}${rootPath}",
"typescript.tsdk": "node_modules\\typescript\\lib"
}
.gitignore
https://github.com/github/gitignore/blob/master/Node.gitignore から取る。一番下に/out
を追加する。ただし、typescriptをコンパイルしたjsもコミットする必要がある場合は/out/
は不要なので注意。
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# TypeScript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
/out/
gulp
gulpConfig.json
ファイルで転送先のホスト名と、ホストの中でのファイル設置場所を指定する。
{
"sshHost": "example.com",
"targetDirectory": "/home/ec2-user/app/"
}
gulpのタスクはdeploy
の一つだけ。この中で、typescriptをコンパイル、指定されたホスト名の設定をsshconfigファイルから読み込み、ssh接続、転送先のディレクトリを削除、コンパイル済みのファイルを指定のディレクトリに転送 という処理をしている。転送後にpm2 restart xxx
のようなコマンドが必要な場合があるが、それは非対応。
危険を犯してまで転送先のディレクトリを削除している理由は、ローカルから削除したファイルがサーバで残っているのが嫌だから。
const gulp = require('gulp');
const gulpSSH = require('gulp-ssh');
const SSHConfig = require('ssh-config');
const path = require("path");
const fs = require("fs");
const childProcess = require("child_process");
const 転送先host = require("./gulpConfig.json").sshHost;
const 転送先ディレクトリ = require("./gulpConfig.json").targetDirectory;
if (転送先host == "" || 転送先ディレクトリ == "") {
throw new Error(`gulpConfig.jsonの値がカラです。`);
}
const ssh = getSSHInstance();
gulp.task("deploy", async (done) => {
await typescriptをコンパイル();
await sshから一つのコマンドを実行(`rm -rf "${転送先ディレクトリ}" ; exit;\n`);
await ファイルを転送();
await sshから一つのコマンドを実行(`cd "${転送先ディレクトリ}" ; npm install --production; exit;\n`);
done();
});
function ファイルを転送() {
return new Promise((resolve, reject) => {
gulp.src(['./**/*.*', '!**/node_modules/**', '!**/.vscode/**'])
.pipe(ssh.dest(転送先ディレクトリ))
.on("finish", () => { resolve(); });
});
}
function sshから一つのコマンドを実行(command) {
return new Promise(resolve => {
const client = ssh.getClient();
sshClientからshellのchannelを取得(client).then(channel => {
// dataを受信しないとcloseが発火しない。何故・・・
channel.on("data", (data) => {
console.log(data.toString("utf-8"));
});
channel.on("close", () => {
channel.end();
client.end();
resolve();
});
channel.end(command);
});
});
}
function sshClientからshellのchannelを取得(client) {
return new Promise((resolve, reject) => {
client.gulpReady(() => {
client.shell((err, channel) => {
if (err) {
console.error(`sshのシェルを取得する事に失敗しました。`);
reject(err);
} else {
resolve(channel);
}
});
});
});
}
function typescriptをコンパイル() {
return new Promise((resolve, reject) => {
console.log(`typescriptをコンパイル。`);
const cp = childProcess.spawn(`node`, [`./node_modules/typescript/bin/tsc`]);
cp.stderr.on("data", (data) => {
console.error(data.toString("utf-8"));
});
cp.stdout.on("data", (data) => {
console.log(data.toString("utf-8"));
})
cp.on("exit", (code) => {
if (code !== 0) {
console.error(`typescriptのコンパイルに失敗しました。`);
reject();
} else {
resolve();
}
});
});
}
function getSSHInstance() {
if (process.platform !== "win32") {
throw new Error('win32ではありません。');
}
const sshConfigPath = path.join(process.env["USERPROFILE"], ".ssh", "config");
if (fs.existsSync(sshConfigPath) == false) {
throw new Error('ssh_configがありません。');
}
const parseSshConfig = SSHConfig.parse(fs.readFileSync(sshConfigPath).toString("utf-8")).find({ Host: 転送先host });
const port = parseSshConfig.config.filter(a => a.param === "Port").map(a => a.value).reduce((_, b) => b, null);
const IdentityFile = parseSshConfig.config.filter(a => a.param === "IdentityFile").map(a => a.value).reduce((_, b) => b, null);
const username = parseSshConfig.config.filter(a => a.param === "User").map(a => a.value).reduce((_, b) => b, null);
return new gulpSSH({
sshConfig: {
host: 転送先host,
port: port,
username: username,
privateKey: fs.readFileSync(IdentityFile).toString("utf-8")
}
});
}
pm2
おまけ。
{
"name": "project-name",
"script": "./out/index.js"
}
Author And Source
この問題について(typescriptのコードをvscodeでデバッグしつつコンパイルしてサーバに転送する雛形), 我々は、より多くの情報をここで見つけました https://qiita.com/Fushihara/items/28b38cf04ed8a3e5fa2f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .