我想提供一个方法,因为我找不到任何完整的信息。我认为这在Stackoverflow文档中似乎最合适。但是,它已被停用*-)-停用文档(*)。
相反,我将其写为StackOverflow问答。
如何将Typescript,NodeJS和Express应用程序部署到Heroku
我创建了一个项目(https://gitlab.com/OehmSmith_Examples/herokumovies),其中包括描述需要完成的自述文件,我将在此处进行复制。作为良好的StackOverflow做法,我还将在本文底部提供所有代码的副本。
本教程可从https://amenallah.com/node-js-typescript-jest-express-starter/作为基础应用程序开始工作。我与该网站或作者没有任何隶属关系。我选择它是因为它简单易用。这也是良好的OO Typescript代码的示例。
大多数教程甚至https://www.typescriptlang.org/docs/handbook/typescript-in-5-minutes.html中的官方文档都说要在全球范围内安装打字稿:
> 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}`)
});
为此,我已将PORT添加到npm scripts
,包括添加,start:dev
以便您可以像已编译的打字稿中的Heroku一样运行它。
"start:dev": "PORT=5000 node dist/index.js",
"dev": "PORT=5000 nodemon --exec ts-node src/index.ts --watch src",
或者可以在.env文件中设置它:
PORT=5000
Heroku不会安装dev依赖项(其他任何云提供商也不会)。因此,您需要将一些依赖项移至主块。例如,一个NestJS
应用程序具有以下这些作为Dev Dependencies,它们需要移动:
@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
您可能需要将返回的git url添加为远程对象(使用进行检查git remote -v
):
git remote add heroku <git url>
查找或搜索buildpacks(下一步已经指定了我使用的内容):
搜索:
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
使用邮递员或类似人员进行测试,或从命令行运行此命令:
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还默认使用这些软件的最新版本之一。您可以在package.json
文件的顶层显式设置版本,例如:
"engines": {
"node": "10.x",
"npm": "6.x"
},
尽管如果您未指定npm
版本,则Heroku将为节点的版本使用合理的默认值。
我只用了几个小时就完成了。我需要解决的主要问题是打字稿必须是本地的,而不是全局的。还有构建包。尽管每个云提供商都需要使用PORT,但是PORT也是一个问题,process.env.PORT
因此这对我来说很明显。
Azure是一场噩梦,耗时数日,但这主要是因为我所在的工作场所坚持使用Windows服务器。长话短说,我不会讲。
AWS如此令人费解。经过一天的尝试,我没有得到我曾经工作过的实例。但是我确实需要再试一次。我尝试的应用使用了https://tsed.io/库。简单的Node / Typescript / Express应用程序应该很容易工作。
(*)-尽管文档发生在2年前,但我认为它并不是我所使用的东西,因此尽管如此,文档的淘汰还是有些令人惊讶。我一直认为,问答是最简单的文档记录场所。
.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] 删除。
我来说两句