Skip to content
This repository was archived by the owner on Nov 28, 2020. It is now read-only.
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 14333c4

Browse files
committedMay 30, 2019
TypeScript + VSCode + Nuxt.js + Workspace instrumentation
* Make PWA optional, refactor comment folding. * Review README * Figure out how static/sw.js works (need documentation)
1 parent 49d229b commit 14333c4

20 files changed

+389
-87
lines changed
 

‎.gitignore

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ yarn-error.log
77
*.iml
88
.nuxt
99
.vscode
10+
!.vscode/settings.json
11+
!.vscode/extensions.json
12+
!.vscode/tasks.json
1013

1114
static/manifest*.json
1215
static/sw.js

‎.vscode/extensions.json

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"recommendations": [
3+
"CoenraadS.bracket-pair-colorizer",
4+
"editorconfig.editorconfig",
5+
"gamunu.vscode-yarn",
6+
"gamunu.vscode-yarn",
7+
"jasonnutter.search-node-modules",
8+
"mrmlnc.vscode-attrs-sorter",
9+
"octref.vetur",
10+
"richie5um2.vscode-sort-json",
11+
"sourcegraph.javascript-typescript",
12+
"sysoev.language-stylus"
13+
]
14+
}

‎.vscode/settings.json

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
// https://code.visualstudio.com/docs/getstarted/settings
3+
"editor.trimAutoWhitespace": true,
4+
"editor.renderControlCharacters": true,
5+
"editor.renderWhitespace": "all",
6+
"files.trimTrailingWhitespace": true,
7+
"typescript.tsdk": "node_modules/typescript/lib",
8+
"vetur.validation.style": true,
9+
"vetur.validation.template": true,
10+
"[json]": {
11+
"editor.formatOnSave": true
12+
},
13+
"[vue]": {
14+
"editor.formatOnSave": true
15+
},
16+
"[typescript]": {
17+
"editor.formatOnSave": true,
18+
"editor.formatOnPaste": true
19+
}
20+
}

‎README.md

+35-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Nuxt Hacker News TS
22

3-
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).
3+
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).
44

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

3336
## Build Setup
3437

3538
**Requires Node.js 6+**
3639

3740
```bash
3841
# install dependencies
39-
npm install # or yarn
42+
yarn
4043

4144
# serve in dev mode, with hot reload at localhost:3000
42-
npm run dev
45+
yarn dev
4346

4447
# build for production
45-
npm run build
48+
yarn build
4649

4750
# serve in production mode
48-
npm start
51+
yarn start
4952

5053
# run unit tests
51-
npm run test
54+
yarn test
5255

5356
# validate code with TSLint (with Prettier)
54-
npm run lint
57+
yarn lint
5558

5659
# validate and fix with TSLint (with Prettier)
57-
npm run lintfix
60+
yarn lintfix
61+
```
62+
63+
### Production build
64+
65+
#### SPA
5866

67+
```bash
68+
yarn
69+
yarn build
5970
```
6071

72+
6173
## Links
62-
For Nuxt JS version go [here](https://github.com/nuxt/hackernews)
6374

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

6577
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)
6678

79+
## Docs
80+
81+
- [nuxt-community/pwa-module](https://github.com/nuxt-community/pwa-module) ([docs](https://pwa.nuxtjs.org/modules/workbox.html))
82+
- [vue-i18n](https://github.com/kazupon/vue-i18n) ([docs](https://kazupon.github.io/vue-i18n/))
83+
- [vuex-class](https://github.com/ktsn/vuex-class/)
84+
- [vue-class-component](https://github.com/vuejs/vue-class-component)
85+
86+
### Other useful *TypeScript* + *Nuxt.js* boilerplate/starter-kit projects
87+
88+
- [hisasann/typescript-nuxtjs-boilerplate](https://github.com/hisasann/typescript-nuxtjs-boilerplate)
89+
- [**nuxt/nuxt.js** in *examples/typescript*](https://github.com/nuxt/nuxt.js/tree/dev/examples/typescript)
90+
6791
## License
6892

6993
MIT
70-

‎components/comment.vue

+40-6
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,22 @@
55
{{ comment.time | timeAgo }} ago
66
</div>
77
<div class="text" v-html="comment.content"/>
8-
<div v-if="comment.comments && comment.comments.length" :class="{ open }" class="toggle">
8+
<div
9+
v-if="comment.comments && comment.comments.length"
10+
:class="{ open }"
11+
class="toggle"
12+
>
913
<a
1014
@click="open = !open"
11-
>{{ open ? '[-]' : '[+] ' + pluralize(comment.comments.length) + ' collapsed' }}</a>
15+
>
16+
<!--
17+
We want minimal things going on here
18+
So that when it's time to do i18n, it's just
19+
going to be a matter of making sure we pass
20+
strings through i18n’s $t() helpers.
21+
-->
22+
{{ pluralize(open, comment.comments.length) }}
23+
</a>
1224
</div>
1325
<ul v-show="open" class="comment-children">
1426
<comment
@@ -30,8 +42,21 @@ export default class Comment extends Vue {
3042
3143
open: boolean = true
3244
33-
pluralize(n) {
34-
return n + (n === 1 ? " reply" : " replies")
45+
pluralize (open, n) {
46+
// Should we have vue-i18n;
47+
// We could also leverage Intl.NumberFormat
48+
// https://kazupon.github.io/vue-i18n/guide/number.html#custom-formatting
49+
const number = n // this.$n(n)
50+
51+
// Should we have vue-i18n;
52+
// We could use vue-i18n $tc helper
53+
// Assuming 'replies' would be 'Replies collapsed | Reply collapsed | Replies collapsed'
54+
// https://kazupon.github.io/vue-i18n/guide/pluralization.html
55+
const textContent = n === 1 ? 'reply' : 'replies' // this.$tc('replies', n)
56+
57+
const append = open ? '' : 'collapsed' // this.$t('collapsed')
58+
59+
return `${number} ${textContent} ${append}`.trim()
3560
}
3661
}
3762
</script>
@@ -78,15 +103,24 @@ export default class Comment extends Vue {
78103
padding: 0.3em 0.5em;
79104
border-radius: 4px;
80105
106+
a:before {
107+
// +
108+
// https://unicode-table.com/en/002B/
109+
content: '\002B';
110+
}
111+
81112
a {
82113
color: #828282;
83114
cursor: pointer;
84115
}
85116
86117
&.open {
87-
padding: 0;
88118
background-color: transparent;
89-
margin-bottom: -0.5em;
119+
a:before {
120+
//
121+
// https://unicode-table.com/en/2212/
122+
content: '\2212';
123+
}
90124
}
91125
}
92126
}

‎layouts/default.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
<router-link v-for="(list, key) in feeds" :key="key" :to="`/${key}`">{{ list.title }}</router-link>
99
<a
1010
class="github"
11-
href="https://github.com/nuxt/hackernews"
11+
href="https://github.com/nuxt-community/hackernews-nuxt-ts"
1212
target="_blank"
1313
rel="noopener banner"
14-
>Built with Nuxt.js</a>
14+
>Built with Nuxt.js using TypeScript</a>
1515
</nav>
1616
</header>
1717
<nuxt nuxt-child-key="none" role="main"/>

‎lib/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
import * as runtime from "./runtime"
2+
3+
export { runtime }

‎lib/runtime/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export * from "./logging"
2+
export * from "./nuxt"

‎lib/runtime/logging.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// There must be a way to make a type based on the possible values.
2+
// But, for now, its not like we'll have more than this list
3+
const possibleLevels: string[] = ["debug", "info", "warn", "error", "fatal"]
4+
export type LogLevel = "debug" | "info" | "warn" | "error" | "fatal"
5+
6+
export const levels: ReadonlyArray<string> = [...possibleLevels]
7+
8+
const isLogLevel = (x: any): x is LogLevel => levels.includes(x)
9+
10+
export const ensureValidLogLevel = (input: string): LogLevel => {
11+
const fallbackValue: LogLevel = "info"
12+
if (isLogLevel(input)) {
13+
return input
14+
}
15+
return fallbackValue
16+
}

‎lib/runtime/nuxt/config/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./workbox"

‎lib/runtime/nuxt/config/workbox.ts

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
export const workbox = (
2+
useWorkbox: boolean = false,
3+
isDev: boolean = false
4+
) => {
5+
if (!useWorkbox) {
6+
return {}
7+
}
8+
9+
return {
10+
// https://pwa.nuxtjs.org/modules/workbox.html
11+
dev: isDev,
12+
cacheNames: {
13+
prefix: "hackernews"
14+
},
15+
clientsClaim: true,
16+
config: {
17+
debug: isDev
18+
},
19+
offlinePage: "/offline.html",
20+
skipWaiting: true
21+
}
22+
}

‎lib/runtime/nuxt/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./config"

‎nuxt.config.ts

+45-9
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,42 @@
11
import NuxtConfiguration from "@nuxt/config"
2+
import { LogLevel, ensureValidLogLevel } from "./lib/runtime"
3+
import { workbox } from "./lib/runtime/nuxt/config"
4+
5+
const {
6+
NODE_ENV = "production",
7+
NUXT_ENV_LOG_LEVEL = "error",
8+
NUXT_ENV_ENABLE_WORKBOX = "true",
9+
NUXT_ENV_API_URL = "https://api.hnpwa.com/v0"
10+
} = process.env
211

312
// https://nuxtjs.org/api/configuration-env/
4-
const apiBaseUrl = process.env.NUXT_ENV_API_URL || "https://api.hnpwa.com/v0"
13+
const apiBaseUrl = NUXT_ENV_API_URL
14+
const enableWorkbox: boolean = NUXT_ENV_ENABLE_WORKBOX === "true"
15+
const isDev: boolean = NODE_ENV !== "production"
16+
const logLevel: LogLevel = ensureValidLogLevel(NUXT_ENV_LOG_LEVEL)
17+
18+
const modules: string[] = ["@nuxtjs/component-cache", "@nuxtjs/axios"]
19+
if (enableWorkbox) {
20+
modules.push("@nuxtjs/pwa")
21+
}
22+
23+
const runtimeSwitches: { [key: string]: string | boolean } = {
24+
NODE_ENV,
25+
NUXT_ENV_LOG_LEVEL,
26+
NUXT_ENV_ENABLE_WORKBOX,
27+
NUXT_ENV_API_URL,
28+
apiBaseUrl,
29+
enableWorkbox,
30+
isDev,
31+
logLevel,
32+
modules: (modules || []).join(", ")
33+
}
34+
35+
if (NUXT_ENV_LOG_LEVEL === "debug") {
36+
process.env.DEBUG = "*"
37+
}
538

6-
const isDev = process.env.NODE_ENV !== "production"
39+
console.table({ ...runtimeSwitches }) // tslint:disable-line
740

841
const config: NuxtConfiguration = {
942
mode: "spa",
@@ -37,18 +70,18 @@ const config: NuxtConfiguration = {
3770
color: "#59cc93"
3871
},
3972
manifest: {
40-
name: "Nuxt Hacker News Typescript",
73+
name: "Nuxt Hacker News TypeScript",
4174
short_name: "Nuxt HN TS",
42-
description: "HackerNews clone built with Nuxt.js & Typescript",
75+
description: "HackerNews clone built with Nuxt.js & TypeScript",
4376
theme_color: "#188269"
4477
},
45-
modules: ["@nuxtjs/pwa", "@nuxtjs/component-cache", "@nuxtjs/axios"],
78+
modules,
4679
env: {
4780
apiBaseUrl
4881
},
4982
axios: {
5083
debug: isDev,
51-
proxy: true,
84+
proxy: isDev,
5285
baseURL: apiBaseUrl
5386
},
5487
proxy: {
@@ -59,17 +92,20 @@ const config: NuxtConfiguration = {
5992
}
6093
}
6194
},
95+
workbox: workbox(enableWorkbox, isDev),
6296
plugins: ["~/plugins/filters"],
6397
serverMiddleware: ["~/common/cache"],
6498
render: {
6599
http2: {
66100
push: true
67101
},
68102
static: {
69-
maxAge: "1y",
103+
maxAge: isDev ? 2000 : "1m",
70104
setHeaders(res, path) {
71-
if (path.includes("sw.js")) {
72-
res.setHeader("Cache-Control", `public, max-age=${15 * 60}`)
105+
if (enableWorkbox) {
106+
if (path.includes("sw.js")) {
107+
res.setHeader("Cache-Control", `public, max-age=${15 * 60}`)
108+
}
73109
}
74110
}
75111
}

0 commit comments

Comments
 (0)
This repository has been archived.