完全な情報が見つからなかったので、これに関するハウツーを提供したかったのです。Stackoverflowのドキュメントではこれが最も適切だと思いました。ただし、廃止されました*-)-廃止されたドキュメント(*)。
代わりに、これをStackOverflow Q&Aとして記述します。
Typescript、NodeJS、ExpressアプリをHerokuにデプロイする方法
何をする必要があるかを説明するREADMEを含むプロジェクト(https://gitlab.com/OehmSmith_Examples/herokumovies)を作成しました。ここでそれを再現します。StackOverflowの優れたプラクティスとして、この投稿の最後にすべてのコードのコピーも提供します。
このチュートリアルは、https://amenallah.com/node-js-typescript-jest-express-starter/からベースアプリとして機能します。私はそのサイトや作者とは何の関係もありません。シンプルで機能するので選びました。これは、優れたOOTypescriptコードの例でもあります。
ほとんどのチュートリアルまたはhttps://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.htmlの公式ドキュメントでさえ、typescriptをグローバルにインストールすると述べています。
> npm install -g typescript
Herokuにはtypescriptのグローバルインストールがないため、ローカルに保持する必要があります。サンプルプロジェクトはこれを実行します。
> npm i -D nodemon rimraf typescript ts-node ts-jest jest @types/jest @types/node
@types/node
古いバージョンに固定している場合は、次のようなエラーが表示されます。
~/AppData/Roaming/nvm/v11.15.0/node_modules/typescript/lib/lib.es2015.iterable.d.ts:41:6 - error TS2300: Duplicate identifier 'IteratorResult'.
41 type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
~~~~~~~~~~~~~~
node_modules/@types/node/index.d.ts:170:11
170 interface IteratorResult<T> { }
~~~~~~~~~~~~~~
'IteratorResult' was also declared here.
node_modules/@types/node/index.d.ts:170:11 - error TS2300: Duplicate identifier 'IteratorResult'.
170 interface IteratorResult<T> { }
~~~~~~~~~~~~~~
~/AppData/Roaming/nvm/v11.15.0/node_modules/typescript/lib/lib.es2015.iterable.d.ts:41:6
41 type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
~~~~~~~~~~~~~~
'IteratorResult' was also declared here.
Found 2 errors.
TypeScriptから:重複した識別子 'IteratorResult'。そしてそれに従ってあなたはあなたのバージョンを更新する必要があります@types/node
。これは、古いコードで作業していて、この議論を含めたいと思ったときに私が直面した問題でした。
index.ts
元のコードはポート5000をハードコードしているため、代わりにを次のように変更します。
app.listen(process.env.PORT, () => {
console.log(`server started on port ${process.env.PORT}`)
});
これを可能にするために、コンパイルされたタイプスクリプトからHerokuと同じように実行できるようにnpm scripts
、を追加するなど、PORTをに追加しましたstart:dev
。
"start:dev": "PORT=5000 node dist/index.js",
"dev": "PORT=5000 nodemon --exec ts-node src/index.ts --watch src",
または、.envファイルで設定できます。
PORT=5000
Herokuは開発依存関係をインストールしません(他のクラウドプロバイダーもインストールしません)。したがって、いくつかの依存関係をメインブロックに移動する必要があります。たとえば、NestJS
アプリケーションにはこれらが開発依存関係としてあり、移動する必要があります。
@nestjs/cli
このコンストラクターをMoviesApi.ts
:に追加しました
constructor() {
// setup some dummy data
movies.push({
name: 'Pirates of the caribbean',
rating: 8.5
})
movies.push({
name: 'Star Wars: A new hope',
rating: 8.7
})
}
Herokuにデプロイします
ターミナルで:
heroku login
heroku create moviesheroku // this needs to be unique
返されたgiturlをリモートとして追加する必要がある場合があります(で確認してくださいgit remote -v
)。
git remote add heroku <git url>
ビルドパックを検索または検索します(次のステップでは、使用するビルドパックをすでに指定しています)。
検索:
heroku buildpacks:search typescript
ビルドパックを追加します。
heroku buildpacks:add zidizei/typescript
heroku buildpacks:add heroku/nodejs
ビルドパックを確認します。
heroku buildpacks
ローカルリポジトリにコミットする
git init // if not already done
git add --all
git ci -m "Initial commit. Test project all setup and should be ready to 'serve' but not yet ready to deploy to heroku"
で実行
npm dev # OR
npm run start:dev # It depends on your npm scripts
postmanなどでテストするか、コマンドラインからこれを実行します。
curl http://localhost:5000/movies
それが発生することをテストする npm run build
npmスクリプトを更新して、npm install
Herokuに()をインストールした後、実行する前にビルドするようにします。npm run start
"postinstall": "npm run build" # Depends on your npm scripts
ローカルリポジトリにコミットします。
git add --all
git ci -m "Now it should deploy, build and run on heroku"
herokuにデプロイします。ビルドして起動する必要があります。
git push heroku master
テスト(アプリheroku create
がmoviesheroku
-それに応じて調整すると仮定)
curl https://moviesheroku.herokuapp.com/movies
Procfile
このアプリについてHerokuに伝えることは指定していません。幸い、これがnode + npm
アプリであると判断して、独自のデフォルトを作成します。ただし、これを明示的に定義することができ、複数のアプリなどがある場合は、このアクションを実行する必要があります。以下を含むProcfileを追加できます(これがデフォルトです)。
web: npm start
Herokuは、デフォルトでこれらの最新バージョンの1つを使用します。次のpackage.json
ように、ファイルのトップレベルでバージョンを明示的に設定できます。
"engines": {
"node": "10.x",
"npm": "6.x"
},
ただし、npm
バージョンを指定しない場合、Herokuはノードのバージョンに適切なデフォルトを使用します。
私はこれをほんの数時間で行った。私が解決する必要があった主な問題は、typescriptがグローバルではなくローカルでなければならないということです。そしてビルドパック。PORTも問題ですが、すべてのクラウドプロバイダーがを使用する必要があるため、process.env.PORT
これは私には明らかでした。
Azureは悪夢であり、数日かかりましたが、それは主に、私がWindowsサーバーの使用を主張していた職場が原因でした。長い話と私はそれには入りません。
AWSはとても複雑でした。1日試しても、作業中のインスタンスを取得できませんでした。ただし、再試行する必要があります。私が試していたアプリはhttps://tsed.io/ライブラリを使用していました。Simple Node / Typescript / Expressアプリは非常に簡単に動作するはずです。
(*)-2年以上前に起こったことを考えると、ドキュメントの廃止は少し意外でしたが、私が使用したものではなかったと思います。そして、私はいつもQ&Aがドキュメント化のための最も簡単な場所だと思っていました。
.gitignore
node_modules
dist
coverage
.jest.config.js
module.exports = {
preset: 'ts-jest',
testEnvironment: 'node'
};
package.json
{
"name": "movies",
"version": "1.0.0",
"description": "Example from https://amenallah.com/node-js-typescript-jest-express-starter/ but then modify and / or show steps for how to deploy this Typescript NodeJS Express RESTful app to Heroku.",
"main": "index.js",
"scripts": {
"build": "rimraf dist && tsc",
"postinstall": "npm run build",
"start": "node dist/index.js",
"start:dev": "PORT=5000 node dist/index.js",
"dev": "PORT=5000 nodemon --exec ts-node src/index.ts --watch src",
"test": "jest --watch",
"coverage": "jest --coverage"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/express": "^4.17.2",
"@types/jest": "^24.0.25",
"@types/node": "^13.1.2",
"jest": "^24.9.0",
"nodemon": "^2.0.2",
"rimraf": "^3.0.0",
"ts-jest": "^24.2.0",
"ts-node": "^8.5.4",
"typescript": "^3.7.4"
},
"dependencies": {
"body-parser": "^1.19.0",
"express": "^4.17.1"
}
}
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"outDir": "dist",
"sourceMap": false,
"allowSyntheticDefaultImports": true,
"baseUrl": ".",
"paths": {
"*": [
"node_modules/",
],
"typings/*": [
"src/typings/*"
]
},
},
"include": [
"src/**/*.ts"
],
"exclude": [
"src/test/**/*.spec.ts"
]
}
src/api/MoviesApi.ts
import IResource from "typings/IResource";
let movies: object[] = []
export default class MoviesApi implements IResource {
constructor() {
// setup some dummy data
movies.push({
name: 'Pirates of the caribbean',
rating: 8.5
})
movies.push({
name: 'Star Wars: A new hope',
rating: 8.7
})
}
create(data: any): any {
movies.push(data)
return data
}
findMany(): any[] {
return movies;
}
}
src/test/api/Movies.spec.ts
import IResource from '../typings/IResource'
import MoviesApi from '../api/MoviesApi'
const moviesApi: IResource = new MoviesApi()
describe('Movies API', () => {
it('should create a new movie', () => {
const movieData: object = {
name: 'Pirates of the caribbean',
rating: 8.5
};
const movie: object = moviesApi.create(movieData);
expect(movie).toEqual(movieData)
})
});
src/typings/IResource/index.d.ts
export default interface IResource {
create(data: any): any
findMany(): any[]
}
src/index.ts
import * as express from 'express'
import * as bodyParser from 'body-parser'
import MoviesApi from './api/MoviesApi'
const app = express();
const moviesApi = new MoviesApi();
app.use(bodyParser.json());
app.post('/movies', (req: express.Request, res: express.Response) => {
res.json(moviesApi.create(req.body))
});
app.get('/movies', (req: express.Request, res: express.Response) => {
res.json(moviesApi.findMany())
});
app.listen(process.env.PORT, () => {
console.log(`server started on port ${process.env.PORT}`)
});
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加