Skip to content
This repository has been archived by the owner on Nov 28, 2020. It is now read-only.

Commit

Permalink
TypeScript + VSCode + Nuxt.js + Workspace instrumentation
Browse files Browse the repository at this point in the history
Vuex Module that are strongly typed with TypeScript

* Make PWA optional, refactor comment folding.
* Review README
* Figure out how static/sw.js works (need documentation)
  • Loading branch information
renoirb committed Jun 8, 2019
1 parent 49d229b commit cb5b5e9
Show file tree
Hide file tree
Showing 29 changed files with 641 additions and 251 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ yarn-error.log
*.iml
.nuxt
.vscode
!.vscode/settings.json
!.vscode/extensions.json
!.vscode/tasks.json

static/manifest*.json
static/sw.js
Expand Down
13 changes: 13 additions & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"recommendations": [
"CoenraadS.bracket-pair-colorizer",
"editorconfig.editorconfig",
"gamunu.vscode-yarn",
"jasonnutter.search-node-modules",
"mrmlnc.vscode-attrs-sorter",
"octref.vetur",
"richie5um2.vscode-sort-json",
"sourcegraph.javascript-typescript",
"sysoev.language-stylus"
]
}
20 changes: 20 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
// https://code.visualstudio.com/docs/getstarted/settings
"editor.trimAutoWhitespace": true,
"editor.renderControlCharacters": true,
"editor.renderWhitespace": "all",
"files.trimTrailingWhitespace": true,
"typescript.tsdk": "node_modules/typescript/lib",
"vetur.validation.style": true,
"vetur.validation.template": true,
"[json]": {
"editor.formatOnSave": true
},
"[vue]": {
"editor.formatOnSave": true
},
"[typescript]": {
"editor.formatOnSave": true,
"editor.formatOnPaste": true
}
}
56 changes: 44 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Nuxt Hacker News TS

HackerNews clone built with Nuxt.js and TypeScript showcasing best practices of developing real life modern isomorphic Web Apps with [Nuxt](https://github.com/nuxt/nuxt.js). It features integrations with [TsLint](https://palantir.github.io/tslint/) (linting), [Prettier](https://prettier.io/) (code formatting), [Jest](https://jestjs.io/) (testing), [Axios](https://github.com/nuxt-community/axios-module) (http calls on steroids), [Storybook](https://storybook.js.org/)* (component playground).
HackerNews clone built with Nuxt.js and TypeScript showcasing best practices of developing real life modern isomorphic Web Apps with [Nuxt](https://github.com/nuxt/nuxt.js). It features integrations with [TsLint](https://palantir.github.io/tslint/) (linting), [Prettier](https://prettier.io/) (code formatting), [Jest](https://jestjs.io/) (testing), [Axios](https://github.com/nuxt-community/axios-module) (http calls on steroids), [Storybook](https://storybook.js.org/)\* (component playground).

<p align="center">
<a href="https://codesandbox.io/s/github/nuxt-community/hackernews-nuxt-ts" target="_blank">
Expand All @@ -23,48 +23,80 @@ Coming soon
- Prefetch/Preload JS + DNS + Data
- Critical Path CSS
- PWA experience using [PWA Module](https://github.com/nuxt-community/pwa-module) with almost _zero config_
- Enable optionnaly PWA, e.g. for development that's orthogonal to PWA features
- PRPL
- Hot reloading dev environment
- [TSLint](https://palantir.github.io/tslint/) and [Prettier](https://prettier.io/) integration
- Typescript 3
- TypeScript 3
- VSCode TypeScript bindings
- Storybook Integration (Coming Soon)
- Snapshot and Unit Tests with Jest and [Vue-Test-Utils](https://vue-test-utils.vuejs.org/) (Coming Soon)
- Snapshot and Unit Tests with Jest and [Vue-Test-Utils](https://vue-test-utils.vuejs.org/) (Coming Soon)
- VSCode setup for build into production, and run in dev with debugging helpers and logging

## Build Setup

**Requires Node.js 6+**

```bash
# install dependencies
npm install # or yarn
yarn

# serve in dev mode, with hot reload at localhost:3000
npm run dev
yarn dev

# build for production
npm run build
yarn build

# serve in production mode
npm start
yarn start

# run unit tests
npm run test
yarn test

# validate code with TSLint (with Prettier)
npm run lint
yarn lint

# validate and fix with TSLint (with Prettier)
npm run lintfix
yarn lintfix
```

### Production build

#### SPA

```bash
yarn
yarn build
```

## Links
For Nuxt JS version go [here](https://github.com/nuxt/hackernews)

For [Nuxt.js version, go to **nuxt/hackernews**](https://github.com/nuxt/hackernews)

This repository is originally ported from [vue-hackernews-2.0](https://github.com/vuejs/vue-hackernews-2.0) and [HackerNews Nuxt](https://github.com/nuxt/hackernews)

## Docs

- [vue-property-decorator](https://github.com/kaorun343/vue-property-decorator)
- [vuex-class](https://github.com/ktsn/vuex-class/)
- [vue-class-component](https://github.com/vuejs/vue-class-component)
- [vue-i18n](https://github.com/kazupon/vue-i18n) ([docs](https://kazupon.github.io/vue-i18n/))

### Useful _TypeScript_ + _Nuxt.js_ community curated examples

- [nuxt-community/typescript-template](https://github.com/nuxt-community/typescript-template)
- [nuxt-community/pwa-module](https://github.com/nuxt-community/pwa-module) ([docs](https://pwa.nuxtjs.org/modules/workbox.html))
- [**nuxt/nuxt.js** in _examples/typescript_](https://github.com/nuxt/nuxt.js/tree/dev/examples/typescript)
- [**nuxt/nuxt.js** in _examples/typescript-vuex_](https://github.com/nuxt/nuxt.js/tree/dev/examples/typescript-vuex)

### Other useful _TypeScript_ + _Nuxt.js_ boilerplate/starter-kit projects

- [hisasann/typescript-nuxtjs-boilerplate](https://github.com/hisasann/typescript-nuxtjs-boilerplate)

### Other relevant links to the topic

- https://stackoverflow.com/q/52863117/852395

## License

MIT

46 changes: 40 additions & 6 deletions components/comment.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,22 @@
{{ comment.time | timeAgo }} ago
</div>
<div class="text" v-html="comment.content"/>
<div v-if="comment.comments && comment.comments.length" :class="{ open }" class="toggle">
<div
v-if="comment.comments && comment.comments.length"
:class="{ open }"
class="toggle"
>
<a
@click="open = !open"
>{{ open ? '[-]' : '[+] ' + pluralize(comment.comments.length) + ' collapsed' }}</a>
>
<!--
We want minimal things going on here
So that when it's time to do i18n, it's just
going to be a matter of making sure we pass
strings through i18n’s $t() helpers.
-->
{{ pluralize(open, comment.comments.length) }}
</a>
</div>
<ul v-show="open" class="comment-children">
<comment
Expand All @@ -30,8 +42,21 @@ export default class Comment extends Vue {
open: boolean = true
pluralize(n) {
return n + (n === 1 ? " reply" : " replies")
pluralize (open, n) {
// Should we have vue-i18n;
// We could also leverage Intl.NumberFormat
// https://kazupon.github.io/vue-i18n/guide/number.html#custom-formatting
const number = n // this.$n(n)
// Should we have vue-i18n;
// We could use vue-i18n $tc helper
// Assuming 'replies' would be 'Replies collapsed | Reply collapsed | Replies collapsed'
// https://kazupon.github.io/vue-i18n/guide/pluralization.html
const textContent = n === 1 ? 'reply' : 'replies' // this.$tc('replies', n)
const append = open ? '' : 'collapsed' // this.$t('collapsed')
return `${number} ${textContent} ${append}`.trim()
}
}
</script>
Expand Down Expand Up @@ -78,15 +103,24 @@ export default class Comment extends Vue {
padding: 0.3em 0.5em;
border-radius: 4px;
a:before {
// +
// https://unicode-table.com/en/002B/
content: '\002B';
}
a {
color: #828282;
cursor: pointer;
}
&.open {
padding: 0;
background-color: transparent;
margin-bottom: -0.5em;
a:before {
//
// https://unicode-table.com/en/2212/
content: '\2212';
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions layouts/default.vue
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
<router-link v-for="(list, key) in feeds" :key="key" :to="`/${key}`">{{ list.title }}</router-link>
<a
class="github"
href="https://github.com/nuxt/hackernews"
href="https://github.com/nuxt-community/hackernews-nuxt-ts"
target="_blank"
rel="noopener banner"
>Built with Nuxt.js</a>
>Built with Nuxt.js using TypeScript</a>
</nav>
</header>
<nuxt nuxt-child-key="none" role="main"/>
Expand Down
3 changes: 3 additions & 0 deletions lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import * as runtime from "./runtime"

export { runtime }
12 changes: 12 additions & 0 deletions lib/models/feed.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
export interface Feed {
comments_count: number
domain: string
id: number
points: number
time: number | Date | undefined
time_ago: string
title: string
type: string
url: string
user: string
}
4 changes: 4 additions & 0 deletions lib/models/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export * from "./feed"
export * from "./item"
export * from "./store"
export * from "./user"
18 changes: 18 additions & 0 deletions lib/models/item.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
export interface Items {
[key: number]: Item
}

export interface Item {
comments: any[]
comments_count: number
content: string
domain: string
id: number
points: number
time: number | Date | undefined
time_ago: string
title: string
type: string
url: string
user: string
}
20 changes: 20 additions & 0 deletions lib/models/store.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { User } from "./user"
import { Feed } from "./feed"
import { Items } from "./item"

export interface Dictionary<T> {
[key: string]: T
}

// tslint:disable-next-line: no-empty-interface
export interface StoreStateRoot {}

export interface StoreStateUser {
items: Dictionary<User>
}

export interface StoreStateFeed {
feeds: Dictionary<Feed>
items: Items
selected: number | null
}
6 changes: 6 additions & 0 deletions lib/models/user.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export interface User {
created: string
created_time: number
id: string
karma: number
}
2 changes: 2 additions & 0 deletions lib/runtime/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export * from "./logging"
export * from "./nuxt"
16 changes: 16 additions & 0 deletions lib/runtime/logging.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// There must be a way to make a type based on the possible values.
// But, for now, its not like we'll have more than this list
const possibleLevels: string[] = ["debug", "info", "warn", "error", "fatal"]
export type LogLevel = "debug" | "info" | "warn" | "error" | "fatal"

export const levels: ReadonlyArray<string> = [...possibleLevels]

const isLogLevel = (x: any): x is LogLevel => levels.includes(x)

export const ensureValidLogLevel = (input: string): LogLevel => {
const fallbackValue: LogLevel = "info"
if (isLogLevel(input)) {
return input
}
return fallbackValue
}
1 change: 1 addition & 0 deletions lib/runtime/nuxt/config/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./workbox"
22 changes: 22 additions & 0 deletions lib/runtime/nuxt/config/workbox.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
export const workbox = (
useWorkbox: boolean = false,
isDev: boolean = false
) => {
if (!useWorkbox) {
return {}
}

return {
// https://pwa.nuxtjs.org/modules/workbox.html
dev: isDev,
cacheNames: {
prefix: "hackernews"
},
clientsClaim: true,
config: {
debug: isDev
},
offlinePage: "/offline.html",
skipWaiting: true
}
}
1 change: 1 addition & 0 deletions lib/runtime/nuxt/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from "./config"
Loading

0 comments on commit cb5b5e9

Please sign in to comment.