From 3c47abb7d6c7a44f86a53defa2efe44c2ae214f6 Mon Sep 17 00:00:00 2001 From: TZ <atian25@qq.com> Date: Wed, 4 Apr 2018 20:19:56 +0800 Subject: [PATCH 1/2] feat: use egg 2.6.0 --- hackernews-async-ts/README.md | 31 +++++++--------- hackernews-async-ts/app/controller/news.ts | 10 +++--- hackernews-async-ts/app/extend/filter.ts | 8 +++-- hackernews-async-ts/app/router.ts | 2 +- .../app/service/{HackerNews.ts => News.ts} | 0 .../app/view/layout/layout.tpl | 2 +- hackernews-async-ts/config/config.default.ts | 19 ++++++---- hackernews-async-ts/config/plugin.ts | 11 +++--- hackernews-async-ts/package.json | 35 +++++++++---------- .../{HackerNews.test.ts => News.test.ts} | 6 ++-- .../typings/app/service/index.d.ts | 4 +-- hackernews-async-ts/typings/index.d.ts | 7 +--- 12 files changed, 67 insertions(+), 68 deletions(-) rename hackernews-async-ts/app/service/{HackerNews.ts => News.ts} (100%) rename hackernews-async-ts/test/app/service/{HackerNews.test.ts => News.test.ts} (65%) diff --git a/hackernews-async-ts/README.md b/hackernews-async-ts/README.md index dded0eb..b5946f5 100644 --- a/hackernews-async-ts/README.md +++ b/hackernews-async-ts/README.md @@ -1,38 +1,33 @@ -# egg-example-hackernews-async +# hackernews-async-ts -[Hacker News](https://news.ycombinator.com/) showcase using async/await for egg +[Hacker News](https://news.ycombinator.com/) showcase using typescript && egg ## QuickStart ### Development -```shell -$ npm install -$ npm run tsc:w + +```bash +$ npm i $ npm run dev $ open http://localhost:7001/ ``` -### Deploy +Don't tsc compile at development mode, if you had run `tsc` then you need to `npm run clean` before `npm run dev`. -Use `EGG_SERVER_ENV=prod` to enable prod mode +### Deploy -```shell -$ EGG_SERVER_ENV=prod npm start +```bash +$ npm run tsc +$ npm start ``` ### Npm Scripts -- Use `npm run autod` to auto detect dependencies upgrade - Use `npm run lint` to check code style - Use `npm test` to run unit test +- se `npm run clean` to clean compiled js at development mode once ### Requirement -Please ensure your node version is `>=7.6.0` for async await support without flag. If your node version is `>=7.0.0 < 7.6.0`, you can run npm scripts with harmony flag - -```shell -# start server -npm run dev -- --harmony-async-await -# run test cases -npm run test-local -- --harmony-async-await -``` +- Node.js 8.x +- Typescript 2.8+ diff --git a/hackernews-async-ts/app/controller/news.ts b/hackernews-async-ts/app/controller/news.ts index 1fe7734..851f8fe 100644 --- a/hackernews-async-ts/app/controller/news.ts +++ b/hackernews-async-ts/app/controller/news.ts @@ -6,26 +6,26 @@ export default class NewsController extends Controller { const pageSize = app.config.news.pageSize; const page = parseInt(ctx.query.page, 10) || 1; - const idList = await ctx.service.hackerNews.getTopStories(page); + const idList = await ctx.service.news.getTopStories(page); // get itemInfo parallel - const newsList = await Promise.all(idList.map((id) => ctx.service.hackerNews.getItem(id))); + const newsList = await Promise.all(idList.map((id) => ctx.service.news.getItem(id))); await ctx.render('news/list.tpl', { list: newsList, page, pageSize }); } public async detail() { const { ctx } = this; const id = ctx.params.id; - const newsInfo = await ctx.service.hackerNews.getItem(id); + const newsInfo = await ctx.service.news.getItem(id); // get comment parallel - const commentList = await Promise.all(newsInfo.kids.map((_id) => ctx.service.hackerNews.getItem(_id))); + const commentList = await Promise.all(newsInfo.kids.map((_id) => ctx.service.news.getItem(_id))); await ctx.render('news/detail.tpl', { item: newsInfo, comments: commentList }); } public async user() { const { ctx } = this; const id = ctx.params.id; - const userInfo = await ctx.service.hackerNews.getUser(id); + const userInfo = await ctx.service.news.getUser(id); await ctx.render('news/user.tpl', { user: userInfo }); } } diff --git a/hackernews-async-ts/app/extend/filter.ts b/hackernews-async-ts/app/extend/filter.ts index e74123e..7c22c89 100644 --- a/hackernews-async-ts/app/extend/filter.ts +++ b/hackernews-async-ts/app/extend/filter.ts @@ -2,6 +2,10 @@ import * as moment from 'moment'; -exports.relativeTime = (time) => moment(new Date(time * 1000)).fromNow(); +export function relativeTime(time) { + return moment(new Date(time * 1000)).fromNow(); +}; -exports.domain = (url) => url && url.split('/')[2]; +export function domain (url) { + return url && url.split('/')[2]; +}; diff --git a/hackernews-async-ts/app/router.ts b/hackernews-async-ts/app/router.ts index 50a9d49..cead0f3 100644 --- a/hackernews-async-ts/app/router.ts +++ b/hackernews-async-ts/app/router.ts @@ -3,7 +3,7 @@ import { Application } from 'egg'; export default (app: Application) => { const { controller, router } = app; - // router.redirect('/', '/news'); + router.redirect('/', '/news'); router.get('/news', controller.news.list); router.get('/news/item/:id', controller.news.detail); router.get('/news/user/:id', controller.news.user); diff --git a/hackernews-async-ts/app/service/HackerNews.ts b/hackernews-async-ts/app/service/News.ts similarity index 100% rename from hackernews-async-ts/app/service/HackerNews.ts rename to hackernews-async-ts/app/service/News.ts diff --git a/hackernews-async-ts/app/view/layout/layout.tpl b/hackernews-async-ts/app/view/layout/layout.tpl index d9fcc3d..aae4fb2 100644 --- a/hackernews-async-ts/app/view/layout/layout.tpl +++ b/hackernews-async-ts/app/view/layout/layout.tpl @@ -13,7 +13,7 @@ <a id="yc" href="http://www.ycombinator.com"><img src="https://news.ycombinator.com/y18.gif"></a> <h1><a href="/news">Hacker News</a></h1> <span class="source"> - Built with <a href="https://eggjs.org/" target="_blank">egg</a> | <a href="https://github.com/eggjs/egg-boilerplate-simple" target="_blank">Source</a> + Built with <a href="https://eggjs.org/" target="_blank">Egg</a> | <a href="https://github.com/eggjs/examples/tree/master/hackernews-async-ts" target="_blank">Source</a> </span> </div> {% block content %}{% endblock %} diff --git a/hackernews-async-ts/config/config.default.ts b/hackernews-async-ts/config/config.default.ts index 7265d53..7602ea0 100644 --- a/hackernews-async-ts/config/config.default.ts +++ b/hackernews-async-ts/config/config.default.ts @@ -1,12 +1,15 @@ 'use strict'; + import { EggAppConfig, PowerPartial } from 'egg'; import * as fs from 'fs'; import * as path from 'path'; +// 提供给 config.{env}.ts 使用 export type DefaultConfig = PowerPartial<EggAppConfig & BizConfig>; -// 本应用的自定义配置的定义 +// 应用本身的配置 Scheme export interface BizConfig { + sourceUrl: string; news: { pageSize: number; serverUrl: string; @@ -16,10 +19,17 @@ export interface BizConfig { export default (appInfo: EggAppConfig) => { const config = {} as PowerPartial<EggAppConfig> & BizConfig; + // 应用本身的配置 + config.sourceUrl = `https://github.com/eggjs/examples/tree/master/${appInfo.name}`; + config.news = { + pageSize: 30, + serverUrl: 'https://hacker-news.firebaseio.com/v0', + }; + + // 覆盖框架,插件的配置 config.keys = appInfo.name + '123456'; config.view = { - root: path.join(appInfo.baseDir, 'app/view'), defaultViewEngine: 'nunjucks', mapping: { '.tpl': 'nunjucks', @@ -30,10 +40,5 @@ export default (appInfo: EggAppConfig) => { '/favicon.ico': fs.readFileSync(path.join(appInfo.baseDir, 'app/public/favicon.png')), }; - config.news = { - pageSize: 30, - serverUrl: 'https://hacker-news.firebaseio.com/v0', - }; - return config; }; diff --git a/hackernews-async-ts/config/plugin.ts b/hackernews-async-ts/config/plugin.ts index 31c3046..99c3979 100644 --- a/hackernews-async-ts/config/plugin.ts +++ b/hackernews-async-ts/config/plugin.ts @@ -1,7 +1,8 @@ -exports.static = true; +'use strict'; -exports.nunjucks = { - enable: true, - package: 'egg-view-nunjucks', +export default { + nunjucks: { + enable: true, + package: 'egg-view-nunjucks', + }, }; - diff --git a/hackernews-async-ts/package.json b/hackernews-async-ts/package.json index 1845c04..4e18739 100644 --- a/hackernews-async-ts/package.json +++ b/hackernews-async-ts/package.json @@ -1,17 +1,29 @@ { - "name": "egg-example-hackernews-async-ts", + "name": "hackernews-async-ts", "version": "1.0.0", - "description": "hackernews showcase using async/await for egg", + "description": "hackernews showcase using typescript && egg", "private": true, "egg": { "typescript": true }, + "scripts": { + "start": "egg-scripts start", + "dev": "egg-bin dev -r egg-ts-helper/register", + "tsc": "ets && tsc -p tsconfig.json", + "clean": "ets clean", + "test": "npm run lint -- --fix && npm run test-local", + "test-local": "egg-bin test -r egg-ts-helper/register", + "cov": "egg-bin cov", + "lint": "tslint .", + "ci": "npm run lint && npm run tsc && npm run cov --no-ts", + "debug": "egg-bin debug", + "autod": "autod" + }, "dependencies": { - "egg": "^2.5.0", + "egg": "^2.6.0", "egg-scripts": "^2.5.1", "egg-view-nunjucks": "^2.2.0", - "moment": "^2.21.0", - "source-map-support": "^0.5.4" + "moment": "^2.21.0" }, "devDependencies": { "@types/cheerio": "^0.22.1", @@ -31,18 +43,5 @@ }, "engines": { "node": ">=8.9.0" - }, - "scripts": { - "start": "egg-scripts start", - "dev": "egg-bin dev -r egg-ts-helper/register", - "tsc": "ets && tsc -p tsconfig.json", - "clean": "ets clean", - "test": "npm run lint -- --fix && npm run test-local", - "test-local": "egg-bin test -r egg-ts-helper/register", - "cov": "egg-bin cov", - "lint": "tslint .", - "ci": "npm run lint && npm run cov", - "debug": "egg-bin debug", - "autod": "autod" } } diff --git a/hackernews-async-ts/test/app/service/HackerNews.test.ts b/hackernews-async-ts/test/app/service/News.test.ts similarity index 65% rename from hackernews-async-ts/test/app/service/HackerNews.test.ts rename to hackernews-async-ts/test/app/service/News.test.ts index 2d6bf27..804235c 100644 --- a/hackernews-async-ts/test/app/service/HackerNews.test.ts +++ b/hackernews-async-ts/test/app/service/News.test.ts @@ -3,7 +3,7 @@ import { Context } from 'egg'; import { app, assert } from 'egg-mock/bootstrap'; -describe('test/app/service/HackerNews.test.js', () => { +describe('test/app/service/News.test.js', () => { let ctx: Context; before(async () => { @@ -11,12 +11,12 @@ describe('test/app/service/HackerNews.test.js', () => { }); it('getTopStories', async () => { - const list = await ctx.service.hackerNews.getTopStories(); + const list = await ctx.service.news.getTopStories(); assert(list.length === 30); }); it('getItem', async () => { - const item = await ctx.service.hackerNews.getItem(1); + const item = await ctx.service.news.getItem(1); assert(item.id && item.title && item.url); }); }); diff --git a/hackernews-async-ts/typings/app/service/index.d.ts b/hackernews-async-ts/typings/app/service/index.d.ts index d51448b..2f6ba7f 100644 --- a/hackernews-async-ts/typings/app/service/index.d.ts +++ b/hackernews-async-ts/typings/app/service/index.d.ts @@ -1,10 +1,10 @@ // This file was auto created by egg-ts-helper // Do not modify this file!!!!!!!!! -import HackerNews from '../../../app/service/HackerNews'; +import News from '../../../app/service/News'; declare module 'egg' { interface IService { - hackerNews: HackerNews; + news: News; } } diff --git a/hackernews-async-ts/typings/index.d.ts b/hackernews-async-ts/typings/index.d.ts index ae2f559..57f2414 100644 --- a/hackernews-async-ts/typings/index.d.ts +++ b/hackernews-async-ts/typings/index.d.ts @@ -1,8 +1,3 @@ -// extend egg declare module 'egg' { - type PowerPartial<T> = { - [U in keyof T]?: T[U] extends {} - ? { [V in keyof T[U]]?: T[U][V] extends {} ? Partial<T[U][V]> : T[U][V] } - : T[U] - }; + } \ No newline at end of file From 4a8967a5c144161991871377b13efbdd366bf983 Mon Sep 17 00:00:00 2001 From: TZ <atian25@qq.com> Date: Wed, 4 Apr 2018 22:12:23 +0800 Subject: [PATCH 2/2] feat: update ts scripts --- hackernews-async-ts/.autod.conf.js | 6 +++--- hackernews-async-ts/config/config.default.ts | 8 ++++---- hackernews-async-ts/package.json | 18 +++++++++--------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/hackernews-async-ts/.autod.conf.js b/hackernews-async-ts/.autod.conf.js index 96fdfa1..44bb3fb 100644 --- a/hackernews-async-ts/.autod.conf.js +++ b/hackernews-async-ts/.autod.conf.js @@ -7,23 +7,23 @@ module.exports = { devprefix: '^', exclude: [ 'test/fixtures', + 'coverage', ], dep: [ 'egg', 'egg-scripts', 'egg-view-nunjucks', 'moment', - 'source-map-support', ], devdep: [ 'autod', 'autod-egg', 'egg-bin', - ], - keep: [ 'tslib', 'typescript', ], + keep: [ + ], semver: [ ], test: 'scripts', diff --git a/hackernews-async-ts/config/config.default.ts b/hackernews-async-ts/config/config.default.ts index 7602ea0..5cb0b04 100644 --- a/hackernews-async-ts/config/config.default.ts +++ b/hackernews-async-ts/config/config.default.ts @@ -4,10 +4,10 @@ import { EggAppConfig, PowerPartial } from 'egg'; import * as fs from 'fs'; import * as path from 'path'; -// 提供给 config.{env}.ts 使用 +// for config.{env}.ts export type DefaultConfig = PowerPartial<EggAppConfig & BizConfig>; -// 应用本身的配置 Scheme +// app special config scheme export interface BizConfig { sourceUrl: string; news: { @@ -19,14 +19,14 @@ export interface BizConfig { export default (appInfo: EggAppConfig) => { const config = {} as PowerPartial<EggAppConfig> & BizConfig; - // 应用本身的配置 + // app special config config.sourceUrl = `https://github.com/eggjs/examples/tree/master/${appInfo.name}`; config.news = { pageSize: 30, serverUrl: 'https://hacker-news.firebaseio.com/v0', }; - // 覆盖框架,插件的配置 + // override config from framework / plugin config.keys = appInfo.name + '123456'; config.view = { diff --git a/hackernews-async-ts/package.json b/hackernews-async-ts/package.json index 4e18739..62b092d 100644 --- a/hackernews-async-ts/package.json +++ b/hackernews-async-ts/package.json @@ -9,21 +9,21 @@ "scripts": { "start": "egg-scripts start", "dev": "egg-bin dev -r egg-ts-helper/register", - "tsc": "ets && tsc -p tsconfig.json", - "clean": "ets clean", - "test": "npm run lint -- --fix && npm run test-local", + "debug": "egg-bin debug -r egg-ts-helper/register", "test-local": "egg-bin test -r egg-ts-helper/register", + "test": "npm run lint -- --fix && npm run test-local", "cov": "egg-bin cov", + "tsc": "ets && tsc -p tsconfig.json", + "ci": "npm run lint && npm run tsc && egg-bin cov --no-ts", + "autod": "autod", "lint": "tslint .", - "ci": "npm run lint && npm run tsc && npm run cov --no-ts", - "debug": "egg-bin debug", - "autod": "autod" + "clean": "ets clean" }, "dependencies": { "egg": "^2.6.0", - "egg-scripts": "^2.5.1", + "egg-scripts": "^2.6.0", "egg-view-nunjucks": "^2.2.0", - "moment": "^2.21.0" + "moment": "^2.22.0" }, "devDependencies": { "@types/cheerio": "^0.22.1", @@ -33,7 +33,7 @@ "autod": "^3.0.1", "autod-egg": "^1.1.0", "cheerio": "^1.0.0-rc.2", - "egg-bin": "^4.6.0", + "egg-bin": "^4.6.2", "egg-mock": "^3.16.0", "egg-ts-helper": "^1.4.2", "rimraf": "^2.6.1",