cici 0.1.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/app-build-manifest.json +13 -13
- package/.next/standalone/.next/app-path-routes-manifest.json +1 -1
- package/.next/standalone/.next/build-manifest.json +2 -2
- package/.next/standalone/.next/prerender-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/api/asset/[...path]/route.js +1 -1
- package/.next/standalone/.next/server/app/api/asset/[...path]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/blog/[id]/highlights/[hid]/comments/[cid]/reactions/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/blog/[id]/highlights/[hid]/comments/[cid]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/blog/[id]/highlights/[hid]/replies/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/blog/[id]/highlights/[hid]/resolve/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/blog/[id]/highlights/[hid]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/blog/[id]/highlights/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/graphql/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/mile/prompts.body +1 -1
- package/.next/standalone/.next/server/app/api/upload/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/atom.xml/route.js +3 -3
- package/.next/standalone/.next/server/app/atom.xml/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/atom.xml.body +1 -1677
- package/.next/standalone/.next/server/app/blog/[id]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/blog/[id]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/blog/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/blog/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/editor/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/editor/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/login/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/memos/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/memos/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/robots.txt/route.js +1 -1
- package/.next/standalone/.next/server/app/rss.xml/route.js +2 -2
- package/.next/standalone/.next/server/app/rss.xml/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/rss.xml.body +1 -227
- package/.next/standalone/.next/server/app/sitemap.xml/route.js +5 -5
- package/.next/standalone/.next/server/app/sitemap.xml.body +5 -101
- package/.next/standalone/.next/server/app/unavailable/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app-paths-manifest.json +6 -6
- package/.next/standalone/.next/server/chunks/3464.js +1 -1
- package/.next/standalone/.next/server/chunks/3607.js +1 -1
- package/.next/standalone/.next/server/chunks/719.js +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
- package/.next/standalone/package.json +2 -2
- package/.next/standalone/sample-content/blog/hello-cici.md +25 -0
- package/.next/standalone/sample-content/likes.json +1 -0
- package/.next/standalone/sample-content/memos.json +7 -0
- package/.next/standalone/sample-content/site-config.json +18 -0
- package/README.md +17 -1
- package/bin/cici.js +126 -23
- package/package.json +2 -2
- package/.next/standalone/data/assets/1727016079577.jpg +0 -0
- package/.next/standalone/data/assets/images/2024-12-03/1733256504772.jpg +0 -0
- package/.next/standalone/data/assets/images/2024-12-12/.gitkeep +0 -0
- package/.next/standalone/data/assets/images/2024-12-12/1734033798997.png +0 -0
- package/.next/standalone/data/assets/images/2024-12-21/.gitkeep +0 -0
- package/.next/standalone/data/assets/images/2024-12-21/1734785902890.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/.gitkeep +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734990512413.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734991833894.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734993188114.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734993280313.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734993317984.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734993411252.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734993425042.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734993480342.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734993562660.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734993625024.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734993677103.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734993893285.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734993996131.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734994035144.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734994064317.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734994128679.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734994189257.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734994521799.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-23/1734994530669.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-24/.gitkeep +0 -0
- package/.next/standalone/data/assets/images/2024-12-24/1735032434591.jpeg +0 -0
- package/.next/standalone/data/assets/images/2024-12-24/1735068363518.jpeg +0 -0
- package/.next/standalone/data/assets/images/Cofe-app.png +0 -0
- package/.next/standalone/data/blog/.gitkeep +0 -0
- package/.next/standalone/data/blog/2017-summary.md +0 -59
- package/.next/standalone/data/blog/a-complex-web-app-refactor.md +0 -72
- package/.next/standalone/data/blog/a-day-of-remote-worker.md +0 -82
- package/.next/standalone/data/blog/async-action-in-redux.md +0 -257
- package/.next/standalone/data/blog/cofe.md +0 -398
- package/.next/standalone/data/blog/expensee-shortcut-numbers-guide.md +0 -99
- package/.next/standalone/data/blog/first-golang-project-fx.md +0 -113
- package/.next/standalone/data/blog/work-going-index.md +0 -49
- package/.next/standalone/data/blog//344/270/212/346/265/267/345/210/260/351/230/277/345/247/206/346/226/257/347/211/271/344/270/271.md +0 -114
- package/.next/standalone/data/blog//344/272/214/346/234/210/350/221/241/350/220/204/347/211/231/346/270/270/350/256/260.md +0 -107
- package/.next/standalone/data/blog//345/215/216/344/270/272/351/270/277/350/222/231-harmaryos-next-/347/272/277/344/270/213/346/264/273/345/212/250/345/260/217/350/256/260.md +0 -180
- package/.next/standalone/data/blog//345/233/233/346/234/210/347/232/204/345/260/276/345/267/264/351/200/233/345/276/267/345/233/275-/346/237/217/346/236/227.md +0 -76
- package/.next/standalone/data/blog//345/234/250/344/274/246/346/225/246-shoreditch-/345/221/206/344/270/211/345/244/251.md +0 -40
- package/.next/standalone/data/blog//346/204/217/345/244/247/345/210/251/347/275/227/351/251/254/345/244/217/345/244/251/345/233/233/346/227/245/346/270/270.md +0 -59
- package/.next/standalone/data/blog//346/210/221/345/201/232/344/272/206/344/270/200/346/254/276/346/227/205/350/241/214/350/256/260/345/275/225/345/272/224/347/224/250/357/274/232mile.md +0 -40
- package/.next/standalone/data/blog//350/245/277/347/217/255/347/211/231/344/270/203/345/244/251/347/232/204/346/227/205/350/241/214.md +0 -128
- package/.next/standalone/data/blog//351/200/233/351/200/233/346/265/216/345/267/236/345/262/233.md +0 -78
- package/.next/standalone/data/blog-manifest.json +0 -21
- package/.next/standalone/data/highlights/expensee-shortcut-numbers-guide.json +0 -77
- package/.next/standalone/data/likes.json +0 -56
- package/.next/standalone/data/memos.json +0 -1255
- package/.next/standalone/data/site-config.json +0 -22
- /package/.next/standalone/.next/static/{ACh2hmfOOZR7INKDQAX5I → Pl18p4h2shbbqjypPxStc}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ACh2hmfOOZR7INKDQAX5I → Pl18p4h2shbbqjypPxStc}/_ssgManifest.js +0 -0
- /package/.next/standalone/{data → sample-content/assets}/.gitkeep +0 -0
- /package/.next/standalone/{data/assets/images/2024-12-03 → sample-content/highlights}/.gitkeep +0 -0
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Hello, cici
|
|
3
|
+
date: 2025-01-01T09:00:00.000Z
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
Welcome to **cici** — a git-backed blog and memo app that just works.
|
|
7
|
+
|
|
8
|
+
This is a demo post shipped with cici as sample content. Your real blog posts and
|
|
9
|
+
memos live in your own content repo (or a local `--dir` folder); cici is just the
|
|
10
|
+
tooling that serves and edits them.
|
|
11
|
+
|
|
12
|
+
## What you get
|
|
13
|
+
|
|
14
|
+
- **Blog posts** in Markdown — syntax highlighting, math, and images.
|
|
15
|
+
- **Memos** for quick thoughts, with optional location tagging.
|
|
16
|
+
- **GitHub powered** — your data, your control, always in version control.
|
|
17
|
+
|
|
18
|
+
To start writing, run cici against your own content:
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
npx cici --dir ~/my-blog
|
|
22
|
+
npx cici --repo owner/name --token ghp_xxx
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Open `/editor` and replace this post with your first real one.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"title": "cici",
|
|
3
|
+
"description": "A git-backed blog and memo app that just works. Write posts and memos in Markdown, stored in your own repo and always in version control.",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "Your Name",
|
|
6
|
+
"bio": "A short bio about yourself goes here.",
|
|
7
|
+
"location": "Somewhere on Earth"
|
|
8
|
+
},
|
|
9
|
+
"keywords": ["blog", "memo", "markdown", "github", "cici"],
|
|
10
|
+
"social": {
|
|
11
|
+
"github": "your-github-username",
|
|
12
|
+
"twitter": "your_twitter_handle"
|
|
13
|
+
},
|
|
14
|
+
"links": {
|
|
15
|
+
"github.com": "https://github.com/your-github-username",
|
|
16
|
+
"x.com": "https://x.com/your_twitter_handle"
|
|
17
|
+
}
|
|
18
|
+
}
|
package/README.md
CHANGED
|
@@ -4,6 +4,10 @@ A beautifully simple blog and memo app that just works.
|
|
|
4
4
|
|
|
5
5
|
Write thoughts. Share ideas. Let GitHub handle the rest. Originally inspired by [tinymind](https://github.com/mazzzystar/tinymind), now see it in action at [blog.minghe.me](https://blog.minghe.me).
|
|
6
6
|
|
|
7
|
+
> **cici is pure tooling.** Your blog *content* — posts, memos, site config — lives in
|
|
8
|
+
> a **separate content repo** (or a local folder), not here. This repo ships only the
|
|
9
|
+
> app plus a small `sample-content/` demo fixture used for `next dev` and tests.
|
|
10
|
+
|
|
7
11
|
|
|
8
12
|
## What You Get
|
|
9
13
|
|
|
@@ -20,7 +24,8 @@ git clone https://github.com/metrue/cici.git
|
|
|
20
24
|
cd cici && npm install && npm run dev
|
|
21
25
|
```
|
|
22
26
|
|
|
23
|
-
**That's it.** Visit `localhost:3000
|
|
27
|
+
**That's it.** Visit `localhost:3000` — `next dev` serves the shipped `sample-content/`
|
|
28
|
+
demo fixture. Point cici at your own content repo/folder (below) to write for real.
|
|
24
29
|
|
|
25
30
|
[](https://vercel.com/new/clone?repository-url=https://github.com/metrue/cici)
|
|
26
31
|
|
|
@@ -40,6 +45,17 @@ npx cici --repo metrue/cici
|
|
|
40
45
|
npx cici --repo owner/name --token ghp_xxx --port 4000
|
|
41
46
|
```
|
|
42
47
|
|
|
48
|
+
Two more commands for deploying cici *with* a content repo on a host (e.g. Vercel):
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
# From inside a content repo: stage cici's prebuilt Next output into ./ for the host
|
|
52
|
+
npx cici build
|
|
53
|
+
|
|
54
|
+
# Boot the server from preset env (CICI_REPO/CICI_TOKEN/CICI_DIR/PORT/HOST) —
|
|
55
|
+
# no --dir/--repo needed; the host supplies the backend via env
|
|
56
|
+
npx cici start
|
|
57
|
+
```
|
|
58
|
+
|
|
43
59
|
The content contract (same for `--dir` and `--repo`):
|
|
44
60
|
|
|
45
61
|
```
|
package/bin/cici.js
CHANGED
|
@@ -6,9 +6,12 @@
|
|
|
6
6
|
* npx cici --repo <owner/name> serve a remote GitHub content repo (read-only)
|
|
7
7
|
* npx cici --repo <owner/name> --token <t> ...and edit it
|
|
8
8
|
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
9
|
+
* npx cici start boot the server from preset env (platform deploy)
|
|
10
|
+
* npx cici build stage cici's prebuilt output into a content repo
|
|
11
|
+
*
|
|
12
|
+
* cici is pure tooling — the blog *content* lives in a separate repo (or a local
|
|
13
|
+
* folder). The backend is chosen at runtime by lib/runtime/config.ts from the env
|
|
14
|
+
* vars set below (CICI_DIR / CICI_REPO / CICI_TOKEN). No GitHub OAuth, no Vercel.
|
|
12
15
|
*/
|
|
13
16
|
|
|
14
17
|
'use strict'
|
|
@@ -19,6 +22,9 @@ const crypto = require('crypto')
|
|
|
19
22
|
|
|
20
23
|
const pkg = require('../package.json')
|
|
21
24
|
|
|
25
|
+
/** cici package root (holds the prebuilt .next/standalone output). */
|
|
26
|
+
const CICI_ROOT = path.join(__dirname, '..')
|
|
27
|
+
|
|
22
28
|
function printHelp() {
|
|
23
29
|
process.stdout.write(`
|
|
24
30
|
cici ${pkg.version} — serve and edit your blog from local files or a GitHub repo
|
|
@@ -26,8 +32,17 @@ cici ${pkg.version} — serve and edit your blog from local files or a GitHub re
|
|
|
26
32
|
Usage:
|
|
27
33
|
npx cici --dir <path> [options]
|
|
28
34
|
npx cici --repo <owner/name> [--token <token>] [options]
|
|
35
|
+
npx cici start
|
|
36
|
+
npx cici build
|
|
29
37
|
|
|
30
|
-
|
|
38
|
+
Commands:
|
|
39
|
+
(default) Serve a --dir or --repo target (see below)
|
|
40
|
+
start Boot the server from preset env (CICI_REPO/CICI_TOKEN/CICI_DIR/
|
|
41
|
+
PORT/HOST) — for platform deploys where the host sets env
|
|
42
|
+
build Stage cici's prebuilt Next output (.next/standalone, .next/static,
|
|
43
|
+
public) into the current directory so a host (e.g. Vercel) can serve it
|
|
44
|
+
|
|
45
|
+
Targets (exactly one required for the default command):
|
|
31
46
|
--dir <path> Local content folder (contains blog/, memos.json, …)
|
|
32
47
|
--repo <owner/name> Remote GitHub content repo (read-only unless --token given)
|
|
33
48
|
|
|
@@ -42,6 +57,8 @@ Examples:
|
|
|
42
57
|
npx cici --dir ~/my-blog
|
|
43
58
|
npx cici --repo metrue/cici
|
|
44
59
|
npx cici --repo metrue/cici --token ghp_xxx --port 4000
|
|
60
|
+
npx cici start
|
|
61
|
+
npx cici build
|
|
45
62
|
`)
|
|
46
63
|
}
|
|
47
64
|
|
|
@@ -75,12 +92,102 @@ function fail(msg) {
|
|
|
75
92
|
process.exit(1)
|
|
76
93
|
}
|
|
77
94
|
|
|
78
|
-
|
|
79
|
-
|
|
95
|
+
/** Path to the prebuilt standalone server inside the cici package. */
|
|
96
|
+
function serverPath() {
|
|
97
|
+
return path.join(CICI_ROOT, '.next', 'standalone', 'server.js')
|
|
98
|
+
}
|
|
80
99
|
|
|
81
|
-
|
|
82
|
-
|
|
100
|
+
/**
|
|
101
|
+
* Boot the prebuilt Next.js standalone server on host:port. Fills in ephemeral
|
|
102
|
+
* NextAuth secret/url so getToken() doesn't throw in the no-OAuth CLI modes.
|
|
103
|
+
* The backend itself is resolved from env by lib/runtime/config.ts.
|
|
104
|
+
*/
|
|
105
|
+
function bootServer({ port, host, servingLabel }) {
|
|
106
|
+
process.env.PORT = port
|
|
107
|
+
process.env.HOSTNAME = host
|
|
108
|
+
// Auth is bypassed in these modes, but NextAuth's getToken() still runs —
|
|
109
|
+
// give it a secret + url so it doesn't throw. Ephemeral per run.
|
|
110
|
+
if (!process.env.NEXTAUTH_SECRET) process.env.NEXTAUTH_SECRET = crypto.randomBytes(32).toString('hex')
|
|
111
|
+
if (!process.env.NEXTAUTH_URL) process.env.NEXTAUTH_URL = `http://${host}:${port}`
|
|
112
|
+
|
|
113
|
+
const server = serverPath()
|
|
114
|
+
if (!fs.existsSync(server)) {
|
|
115
|
+
fail(
|
|
116
|
+
'prebuilt server not found (.next/standalone/server.js). ' +
|
|
117
|
+
'If running from source, build first: `npm run build:cli`.'
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
process.stdout.write(`\n cici ${pkg.version}\n serving ${servingLabel}\n → http://${host}:${port}\n\n`)
|
|
122
|
+
|
|
123
|
+
require(server)
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* `cici start` — boot the server purely from preset env (CICI_REPO/CICI_TOKEN/
|
|
128
|
+
* CICI_DIR/PORT/HOST). No --dir/--repo required: the host (e.g. a PaaS) supplies
|
|
129
|
+
* the backend env, and lib/runtime/config.ts resolves it (falling back to the
|
|
130
|
+
* production GitHub default when nothing is set).
|
|
131
|
+
*/
|
|
132
|
+
function runStart() {
|
|
133
|
+
const port = String(parseInt(process.env.PORT, 10) || 3000)
|
|
134
|
+
const host = process.env.HOST || process.env.HOSTNAME || '0.0.0.0'
|
|
135
|
+
|
|
136
|
+
let servingLabel
|
|
137
|
+
if (process.env.CICI_DIR) servingLabel = process.env.CICI_DIR
|
|
138
|
+
else if (process.env.CICI_REPO) servingLabel = `${process.env.CICI_REPO}${process.env.CICI_TOKEN ? '' : ' (read-only)'}`
|
|
139
|
+
else servingLabel = 'backend from environment'
|
|
83
140
|
|
|
141
|
+
bootServer({ port, host, servingLabel })
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* `cici build` — stage cici's prebuilt Next output into the CONSUMER's current
|
|
146
|
+
* directory so a host (e.g. Vercel) can serve the content repo with cici's tooling.
|
|
147
|
+
*
|
|
148
|
+
* cici publishes its prebuilt standalone server; a content repo doesn't rebuild
|
|
149
|
+
* Next itself — it just needs cici's compiled output copied alongside its content.
|
|
150
|
+
* We copy the three deployable artifacts into the cwd:
|
|
151
|
+
* <cici>/.next/standalone → <cwd>/.next/standalone
|
|
152
|
+
* <cici>/.next/static → <cwd>/.next/static
|
|
153
|
+
* <cici>/public → <cwd>/public
|
|
154
|
+
*/
|
|
155
|
+
function runBuild() {
|
|
156
|
+
const server = serverPath()
|
|
157
|
+
if (!fs.existsSync(server)) {
|
|
158
|
+
fail(
|
|
159
|
+
'cannot build: cici has no prebuilt server (.next/standalone/server.js).\n' +
|
|
160
|
+
' This normally ships inside the installed `cici` package. If you are running\n' +
|
|
161
|
+
' from source, build it first with `npm run build:cli`.'
|
|
162
|
+
)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const cwd = process.cwd()
|
|
166
|
+
const copies = [
|
|
167
|
+
{ from: path.join(CICI_ROOT, '.next', 'standalone'), to: path.join(cwd, '.next', 'standalone') },
|
|
168
|
+
{ from: path.join(CICI_ROOT, '.next', 'static'), to: path.join(cwd, '.next', 'static') },
|
|
169
|
+
{ from: path.join(CICI_ROOT, 'public'), to: path.join(cwd, 'public') },
|
|
170
|
+
]
|
|
171
|
+
|
|
172
|
+
const done = []
|
|
173
|
+
for (const { from, to } of copies) {
|
|
174
|
+
if (!fs.existsSync(from)) continue
|
|
175
|
+
fs.mkdirSync(path.dirname(to), { recursive: true })
|
|
176
|
+
fs.rmSync(to, { recursive: true, force: true })
|
|
177
|
+
fs.cpSync(from, to, { recursive: true })
|
|
178
|
+
done.push(path.relative(cwd, to) || to)
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
process.stdout.write(
|
|
182
|
+
`\n cici ${pkg.version} build\n` +
|
|
183
|
+
` staged cici's prebuilt output into ${cwd}\n` +
|
|
184
|
+
(done.length ? done.map((d) => ` ✓ ${d}\n`).join('') : ' (nothing to copy)\n') +
|
|
185
|
+
`\n A host can now serve this directory (server entry: .next/standalone/server.js).\n\n`
|
|
186
|
+
)
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/** Default command: serve a --dir or --repo target from CLI options. */
|
|
190
|
+
function runServe(args) {
|
|
84
191
|
if (!args.dir && !args.repo) fail('provide exactly one of --dir <path> or --repo <owner/name>. Run `cici --help`.')
|
|
85
192
|
if (args.dir && args.repo) fail('use only one of --dir or --repo, not both.')
|
|
86
193
|
|
|
@@ -107,24 +214,20 @@ function main() {
|
|
|
107
214
|
servingLabel = `${args.repo}${args.token ? '' : ' (read-only)'}`
|
|
108
215
|
}
|
|
109
216
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
// Auth is bypassed in these modes, but NextAuth's getToken() still runs —
|
|
113
|
-
// give it a secret + url so it doesn't throw. Ephemeral per run.
|
|
114
|
-
if (!process.env.NEXTAUTH_SECRET) process.env.NEXTAUTH_SECRET = crypto.randomBytes(32).toString('hex')
|
|
115
|
-
if (!process.env.NEXTAUTH_URL) process.env.NEXTAUTH_URL = `http://${host}:${port}`
|
|
217
|
+
bootServer({ port, host, servingLabel })
|
|
218
|
+
}
|
|
116
219
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
)
|
|
123
|
-
}
|
|
220
|
+
function main() {
|
|
221
|
+
// Detect subcommands before option parsing.
|
|
222
|
+
const cmd = process.argv[2]
|
|
223
|
+
if (cmd === 'start') { runStart(); return }
|
|
224
|
+
if (cmd === 'build') { runBuild(); return }
|
|
124
225
|
|
|
125
|
-
process.
|
|
226
|
+
const args = parseArgs(process.argv.slice(2))
|
|
227
|
+
if (args.help) { printHelp(); return }
|
|
228
|
+
if (args.version) { process.stdout.write(`${pkg.version}\n`); return }
|
|
126
229
|
|
|
127
|
-
|
|
230
|
+
runServe(args)
|
|
128
231
|
}
|
|
129
232
|
|
|
130
233
|
main()
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cici",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"private": false,
|
|
5
|
-
"description": "cici — a git-backed blog CMS. Run `npx cici --dir <dir>` or `--repo <owner/name>` to serve
|
|
5
|
+
"description": "cici — a git-backed blog CMS (pure tooling; your posts live in a separate content repo). Run `npx cici --dir <dir>` or `--repo <owner/name>` to serve/edit, or `cici build` / `cici start` to deploy.",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
8
|
"url": "git+https://github.com/metrue/cici.git"
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
@@ -1,59 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: 2017 年终总结
|
|
3
|
-
date: 2017-12-30T09:20:02.233Z
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
2017 是很忙碌的一年,离开很自由的 Splunk,来到了现在的 [设计家](https://www.homestyler.com/)团队,换了团队,换了行业,也换工作方式,很多地方需要适应,不管怎样,每一个新的开始都是一个挑战。所以我还是怀着愉快的心情来写这篇年终总结吧.
|
|
7
|
-
|
|
8
|
-
### 工作
|
|
9
|
-
也许全屋定制团队是整个居然设计家上海最忙碌的 Scrum Team 吧,查看打卡就知道我们的成员有多少次都是工作到最晚的。虽然没有强制性的 996, 但是平均下来我们相对 996 过犹不及。
|
|
10
|
-
|
|
11
|
-
* 重构 3D 工具
|
|
12
|
-
|
|
13
|
-
3D 工具作为一个拥有复杂功能,而且历史长久的项目,它拥有这超过 25w 的 JavaScript 代码,无数的 CSS 文件,无数的各类资源文件。而且各种管理风格千差万别。 JavaScript 部分: 既有基于 Google Closure 构建方式的代码,又有 jQuery 风格的大量操作 DOM 的代码,还有很多 ES3/ES5 的代码,还有今年来才引入的 ES6/ES7 风格的代码,还有无穷的原生的 JavaScript 代码。而在 CSS 方面,有原生 CSS 写法,也有 Less/Saas。
|
|
14
|
-
而在代码架构方面,3D Tools 实际的架构是这样的:
|
|
15
|
-
```
|
|
16
|
-
App = App Core + Plugins
|
|
17
|
-
|
|
18
|
-
App Core = (App Transaction Management) + App Data Model + App Views
|
|
19
|
-
```
|
|
20
|
-
为了更好支撑未来更复杂的需求,更快的开发效率,我们对这个代码库进行调整,细节可以在我的这篇文章 [记一次大规模重构](https://blog.minghe.me/a-complex-web-app-refactor/) 了解到,当时真是初生牛犊不怕虎啊,刚到公司不到一个月,才敢对多年历史的复杂项目大刀阔斧的改造。虽然期间又一些问题,不过对于我个人而言,这样的经验无疑是珍贵的,在很短的时间就了解到整个产品的各方各面,对于我如今的开发都是非常有帮助的。
|
|
21
|
-
|
|
22
|
-
* 橱柜定制从 3D 工具应用独立出来
|
|
23
|
-
|
|
24
|
-
橱柜定制作为整个全屋定制项目的排头兵,为了适应以后的快速迭代,我们把橱柜定制从原来作为 3D 工具的一个 plugin 独立出来成为了一个独立的应用,独立的 CodeBase, 独立的 CI/CD。 这个过程充满的艰辛和刺激,估计只有我和 Jerry 知道吧。 从以前作为一个依赖于 3D 工具的 plugin, 如何能够以最小的依赖,而且非功能退化的独立出来成为一个专用应用,这是不小的挑战,但是我们做到了。
|
|
25
|
-
|
|
26
|
-
* 我们从 0 开始搭建整个 3D 定制的参数化引擎
|
|
27
|
-
|
|
28
|
-
任何的引擎都可以这么表征
|
|
29
|
-
```
|
|
30
|
-
engine = f(input, rules)
|
|
31
|
-
```
|
|
32
|
-
不同使用场景 (Domains) 的引擎会有不同的引擎规则 (Rules),而对于家装设计领域,我们的 Rules 来源是各个家装设计公司和生产厂商。如果在这个特殊的领域需求里面抽象出更加适合工程实现的引擎模式成为我们的最头痛的事情,好在团队中的老司机在 Autodesk 已经塌坑无数,在短短的两个月时间里,我们做好了整个参数化引擎,并且在橱柜定制 App 中成功使用,为即将开始的全屋定制打下坚实的基础。
|
|
33
|
-
|
|
34
|
-
* 内部 Hackathon 二等奖
|
|
35
|
-
|
|
36
|
-
到了[设计家团队](https://shejijia.com)之后就一直想在公司内部搞一场 Hackathon,所以当同事和我说他也想搞的时候,我们就一拍即合,和公司申请了经费,而且老板也支持。虽然其中有一些意外,但是整体还是成功的,而且老板也把 Hackathon 变成了每年两次的常规活动。更值得一提的是我们团队的作品: 小居 - 家装设计语音助理, 也很荣幸的获得二等奖,很是意外。语音交互也许是未来的一个很重要的交互入口,所以一早就有给我们公司的产品条件语音交互功能的想法,所以索性就在这次 Hackathon 实践一下,所以离我哪行中想要达到的样子还差的很远,但是基本的流程已经成型,而且玩了简单的交互。也算是一次成功的尝试吧。
|
|
37
|
-
|
|
38
|
-
### 开源项目
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
* [fx](https://github.com/metrue/fx)
|
|
42
|
-
|
|
43
|
-
在 [GoHack2017黑客马拉松](http://gohack2017.golangfoundation.org/) 虽然没有获奖,但是在那场比赛中完成的 [fx](https://github/com/metrue/fx) 成为我去年的小小高光时刻: 在 [Show HN: Fx - Poor man's serverless framework](https://news.ycombinator.com/item?id=15686661)发布了之后,迅速串升到Github Go Trend 榜单的第一名,并且持续在榜单首页超过一个星期,Stars 数目如今也吵过 1k, 当然更值得纪念的是,我和 [@TJ](https://github.com/tj) 大神终于有同框了,哈哈。
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
* [YoYo](https://github.com/metrue/YoYo)
|
|
47
|
-
|
|
48
|
-
而 YoYo 则是一个自己的一个需求:想要一个很干净纯洁的博客留言系统,不要有各种乱七八糟的社交按钮或者广告,所以我就着手自己写一个系统,留下 email 和你想说的话就可以留言,一个纯 JavaScript 的项目,可以在这篇文章[2017-04-18-YoYo:自己打造一个评论服务](https://minghe.me/2017-04-18-YoYo:%E8%87%AA%E5%B7%B1%E6%89%93%E9%80%A0%E4%B8%80%E4%B8%AA%E8%AF%84%E8%AE%BA%E6%9C%8D%E5%8A%A1.html)详细了解。
|
|
49
|
-
|
|
50
|
-
* [Singular.Fm](https://singular.fm/)
|
|
51
|
-
|
|
52
|
-
是的,我参与的 podcast 终于上线了,很早之前就想要做一档 podcast, 但是一直没有狠下心来实施,后来和 [@梯田](https://weibo.com/titantse?refer_flag=1005050005_) 闲聊,正好他也有兴趣,所以一拍即合,说干就干,我们在年前终于录制了一期。希望可以持续做下去。
|
|
53
|
-
|
|
54
|
-
* [MindPalace](https://mpapp.tk/)
|
|
55
|
-
|
|
56
|
-
[@Jakehao](https://twitter.com/haojianzong?lang=en) 从深圳来上海玩,下飞机之后突然说有一个idea,稀里哗啦的和我说一通,我没有听太明白,索性就花了一张图给我看,然后我明白了,这就是一个关于人的日志记录工具啊,Splunk 是记录机器日志的,要是有一个app可以让记录人的日志(心思)变得容易,而且随时可以检索,那么一定棒极了,所以当即就决定和他一起做这个app. 然后我们两个都好忙,发布了第一个 Test Flight 了之后,我们还没有太多的时间的高强度的继续开发。只能周末的时候一起搞搞。
|
|
57
|
-
|
|
58
|
-
### 后记
|
|
59
|
-
做工程师最好玩的地方在于,我们随心所欲的创造,一台电脑,一杯咖啡,一个好玩的创意,就可以让我们在一个地方默默的写几天代码,因为这就是我们的世界,简单而自由的世界。
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: 记一次大规模重构
|
|
3
|
-
date: 2017-07-05T10:17:04.233Z
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
## 前言
|
|
7
|
-
一个健康发展的项目,是不应该有大规模重构的。一个健康的项目,它随时随地的进行着一些小规模的重构,循序渐进,不断改进,积少成多,不断保持项目的活力。但是现实情况是: 我们安逸于现状这样子,虽然它有一些小问题,但是我想我们能够忍受,我们的项目成员不想/敢做出改变,因为它(可能)会触发一些问题。直到有一天,我们不能忍了,因为我们离主流的技术已经很远,我们目前不能使用好的技术方案,我们的开发效率已经太低,我们有很多 bug 不能合理修复,就算修复也可能会带来更多的 bug。所以我们决定来一次大的重构。
|
|
8
|
-
|
|
9
|
-
因为我们都这样:小毛小病的,没有什么大碍。直到病入骨髓了,我们痛下决心,做一个大手术。其实小毛小病,生活注意一下,或者吃两服药,就可以药到病除,然后手术却没有那么轻松,如果运气不好,轻则留下浅浅伤疤,重则可能危及生命。就算手术顺利,也需要好长的一段恢复期啊。
|
|
10
|
-
|
|
11
|
-
但是如果真要进行一次大手术,我们应该要怎么做才能平安度过呢?说说我自己的真实故事吧。
|
|
12
|
-
|
|
13
|
-
## 动手术
|
|
14
|
-
我上个月来到现在的设计家上海团队。我的第一个大任务: 前端代码的分拆。设计家的整个前端是一个超复杂的 Web 应用,单单是 JavaScript 的代码行数就超过了 20w 行,不包含第三方库。在没有做任何的代码分离之前,我们所有的代码都是放在一起的,包括应用的核心框架,图形的底层操作API,业务组件(UI及业务逻辑)都放在一起。由于历史的原因,不同时期的代码不仅风格迥异,而且打包工具也不统一。这样的一个巨大的混杂的代码库会导致很多问题, 比如
|
|
15
|
-
|
|
16
|
-
* 构建工具复杂
|
|
17
|
-
* 构建时间长
|
|
18
|
-
* 测试代码难度很大
|
|
19
|
-
* 引入新技术阻力很大
|
|
20
|
-
|
|
21
|
-
等等这些可见的问题,还是一些隐藏的问题,比如不同的代码风格,到沟通成本上升。各模块之间的依赖交错复杂等等。
|
|
22
|
-
|
|
23
|
-
经过一个月的努力,终于把一个超级巨无霸单一项目分拆成了五个独立的项目,一个主项目(主要是网站的业务代码,是整个 3D 设计家的入口), 以及一个核心库项目(它是整个 3D 设计家的框架层代码),还有其他三个小的基础 API 项目,除了主项目,其他的项目都以 npm 包的形式为外界提供服务。每个项目自己的构建方式对外界透明的。
|
|
24
|
-
|
|
25
|
-
### 代码层
|
|
26
|
-
在进行分拆模块的时候,如下因素.
|
|
27
|
-
|
|
28
|
-
* 是否和业务无关
|
|
29
|
-
* 是否可以复用
|
|
30
|
-
|
|
31
|
-
显然框架层面的代码最应该被独立出来,因为它的接口必须保持一定的稳定性,而且和业务逻辑完全无关,当然它的特殊的构建方式也让我第一时间把它分拆了出来成为独立的项目,对外以提供 npm 包的形式服务。这样我就可以第一时间在主项目中使用统一的构建工具来完成构建 (webpack)。
|
|
32
|
-
|
|
33
|
-
其次,一些提供特殊功能的组件,比如数学计算,图形操作等这类基础的 API,也立即被提出来。同类型的还有一些有着代理作用的代码,它们连接着我们团队的主项目和其他团队的库,这些代码通常被不同团队的开发者改动。
|
|
34
|
-
|
|
35
|
-
最后主项目就变成了一个纯业务逻辑的项目,主要进行各种功能的维护,新 feature 的开发,是最为 Active 的代码。而分离出去的项目都以独立的 npm 包为外界提供服务,它们的开发较为稳定一些,而不同的项目可以按照团队的技术选择进行多样化的开发,这样在独立项目以上可以多样化技术选择,而同一个项目内部则保持统一的,这样就既兼容了稳定性,而又保持了技术的良好更新迭代。
|
|
36
|
-
|
|
37
|
-
### CI/CD 层
|
|
38
|
-
由于项目的拆分,如何保证各个项目中的代码依赖能够保持同步,保证开发效率的同时能够项目能够保持很好的持续集成和持续部署成为了我们首要解决的问题。
|
|
39
|
-
|
|
40
|
-
#### 自动构建
|
|
41
|
-
分离出去的独立项目,它们的发布行为就演变成了一个 npm 包的自动构建和发布。为了保证项目稳定,每一个分离出去的独立项目都采用 release 和 develop 两种形式的 npm 版本特征,它们分别对应的项目的 releae 和 master 分支。当 master 有新的提交的时候,项目在 CI/CD 系统自动构建然后发布 x.y.z-develop-build-number 这样版本的 npm 包,同理,如果是 release 有新的提交,则会自动发布 x.y.z-release-build-number 这样版本的 npm 包。
|
|
42
|
-
|
|
43
|
-
#### 关联触发
|
|
44
|
-
经过分拆之后,我们项目由原来的一个巨大的 A, 变成了五个小 a.
|
|
45
|
-
|
|
46
|
-
```
|
|
47
|
-
Super Big A => (a1, a2, a3, a4, a5)
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
那么显然,任何小的项目(a2, a3, a4, a5)有更新的时候,我们都必须要触发主项目 (a1) 的构建和并且进行相关的自动化测试。所以在我们的 CI/CD 系统中,我们在 Jenkins 的 job 配置中进行了项目的关连触发。并且主项目(a1)的构建会根据当前所在的 branch (release 还是 master)自动安装与其对应的其他项目(a2, a3, a4,a5)的最新依赖包。然后进行构建和自动部署到对应的开发环境(alpha) 或者生产环境。
|
|
51
|
-
|
|
52
|
-
## 反思
|
|
53
|
-
这次的大手术,整体来说结果是好的,虽然其中遇到了不少的问题,但是趟过了这些坑之后,也让我自己在更多的方面了解了自己,了解了团队,与此同时在提醒自己在哪些地方需要努力。我自己总结了下面几点我们没有做好的地方:
|
|
54
|
-
|
|
55
|
-
* 让一个项目新手来独立完成
|
|
56
|
-
|
|
57
|
-
团队选择刚刚加入团队的我来进行这次大手术,确实不能说是一个正确的选择。虽然我自己对于大型前端的架构有一定架构能力,而且对于主流的构建工具也很熟悉。但是项目的重构不是一个小手术,我们需要一个对整个项目都十分熟悉的人来进行主导,而且最好能够有一个得力的助手来一起完成。因为任何的项目都有很多隐含的坑,特别这种需要大手术的项目,很多的坑稍微一动还有可能会致命,只有对项目十分熟悉的人,才能够知道如何避开(或者直接解决)哪些坑而不耽误重构。
|
|
58
|
-
当然,项目组最开始是安排了对项目了解最深的工程师来和我一起来进行的,不过进行到一半的时候,他离开了团队,最后只得我一个人来进行。这是一个谁也没有想到的意外。所以当重构的过程中,如果出现任何的问题,我几乎都会花两倍的时间去解决问题,因为我首先需要去知道到底为什么出现问题,原来采用什么方法来解决,现在我需要选择什么替代的方法来解决。更糟糕的是,我现在需要花大量的时间去和其他不固定的同事去沟通来保证各个模块在重构的过程不受到伤害。
|
|
59
|
-
|
|
60
|
-
* 没有设定好重构的目标
|
|
61
|
-
|
|
62
|
-
在进行这次重构,我们并没有设立一个可以量化的目标,我们仅仅只是有这么一个愿景: 重构之后,项目还能和以前一样运转正常,并且开发效率能有所提高。但是这样一个笼统的希望对于整个重构没有任何帮助。我们需要设定一个可以量化的目标,比如所有的测试不能被破坏,构建的时间不能超过10分钟,构建工具必须统一等等。
|
|
63
|
-
|
|
64
|
-
* 没有测试
|
|
65
|
-
|
|
66
|
-
这是一个老生常谈的问题了,没有完备的测试,每一次的改动都会让你惊心胆战。因为你很难确定你的改动会不会造成什么伤害。这也是后续我们希望可以在团队中推广的,也许每一次的开发都做到 TDD 很难,但是必要的单元测试希望可以做到。
|
|
67
|
-
|
|
68
|
-
* 没有做到完全的沟通
|
|
69
|
-
|
|
70
|
-
由于项目的重构会影响到每一个开发者,所以最好让我们一个团队成员都能够理解到这次改动可能造成的影响,不然出现任何的问题,很多人都会感觉很意外,而且束手无策,这样无疑对于重构产生的问题的处理没有任何帮助,而且可能会雪上加霜。
|
|
71
|
-
|
|
72
|
-
虽然遇到了不少问题,甚至可能有的同事可能会反感:项目运行的好好的,干嘛搞事情啊。但是总体的结果是好的,这不仅对于让我们项目更加健康的发展做好了很好的基础,而且在今后也会大大的提高我们的开发效率,同时保证产品的快速稳定迭代。
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
title: 远程工作者的一天
|
|
3
|
-
date: 2019-06-09T16:30:26.223Z
|
|
4
|
-
external_discussions:
|
|
5
|
-
- platform: v2ex
|
|
6
|
-
url: https://v2ex.com/t/572394
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-

|
|
11
|
-
|
|
12
|
-
很多人喜欢远程工作, 也有很多人多反对远程工作, 远程工作意味着:
|
|
13
|
-
|
|
14
|
-
## 雇主
|
|
15
|
-
|
|
16
|
-
* **只能以员工的产出来衡量员工的价值**
|
|
17
|
-
|
|
18
|
-
雇主雇佣员工的目的是需要这个人的产出,但很多时候很奇怪,很多雇主却花心思去关注这个个员工是不是呆在办公室8个小时,是不是愿意加班.
|
|
19
|
-
|
|
20
|
-
* **提供对异步工作模式友好的基础设施**
|
|
21
|
-
|
|
22
|
-
相比于传统的办公模式,远程工作对公司办公室的硬件条件要求较低,不需要奢华的办公楼,但是需要一些必备的工具来进行高效的异步沟通. 比如 Slack, Zoom, GitHub, JIRA, Google Document 这些沟通,协作,文档工具工具,也需要 VPN 这样的网络工具, 同样 CICD 的工具链也是必不可少,但是这已经是任何技术公司的必备了。
|
|
23
|
-
|
|
24
|
-
* 招聘合适的人
|
|
25
|
-
|
|
26
|
-
对于支持远程工作的企业来说,人才库就从一个城市变成了全世界了,因为你不需要候选人来办公室坐班,所以只要条件满足,全世界的人才原则上你都可以挖掘,当然和所有的招聘一样,风险是存在的,所以 "Hire Slow, Fire Fast" 原则仍然适用,不是每一个人都能适应一个没有同事在身边的工作,有的人是难以自我管理,有的人更喜欢同步工作,有的人不能忍受"孤独"等等。所以招聘一个合适的人变得更难。
|
|
27
|
-
|
|
28
|
-
## 员工
|
|
29
|
-
|
|
30
|
-
* **只能用高效的产出来证明自己的价值**
|
|
31
|
-
|
|
32
|
-
你不再有任何的借口让自己偷懒,因为你的节奏你都已经全权控制,你不能在怪环境,怪时间,你必须成熟的学会管理你的自己时间和精力,管理StateHolders 的期望。
|
|
33
|
-
|
|
34
|
-
* **选择自己最高效的时间和环境来工作**
|
|
35
|
-
|
|
36
|
-
你不需要再去忍受办公室有的同事那些肆无忌惮的噪声(打电话,机械键盘, 或者公共区域的聊天), 你也不用去忍受总有一些必须的会议被安排插入到你的代码时间里面,更不会有人突然就冲到你的工位对你的屏幕指手画脚.
|
|
37
|
-
|
|
38
|
-
你可以选择你喜欢的咖啡店,书店,公园,海边,甚至喜欢的城市或者国家. 你也可以选择低迷的时间去运动,然后在高效的时间工作.
|
|
39
|
-
|
|
40
|
-
* **更便利的肩负照顾家庭的责任**
|
|
41
|
-
|
|
42
|
-
你几乎不会在错过女儿的第一次上台表演,接到幼儿园儿子不舒服的电话,你也可以第一时间去带他去就医,和父母吃晚饭,聊聊家常。你终于除了给他们经济的帮助之外也给予他们陪伴。
|
|
43
|
-
|
|
44
|
-
* **有成块的时间培养自己**
|
|
45
|
-
|
|
46
|
-
省去了在京沪上下班的漫长拥挤的地铁,没有任意插入的会议,没有随意被打扰的办公室环境, 你有了成块(1小时以上)去发展自己,也许是开源项目,也许是系统的学习新知识,也许是艺术和音乐的爱好,利用这样的时间块,你会成为一个更好的自己,你会少了很多的抱怨,多和很多的努力。
|
|
47
|
-
|
|
48
|
-
## 我的典型一天
|
|
49
|
-
|
|
50
|
-
虽然以前所在公司都曾经不同程度的 WFH (Work from Home), 但是真正加入一个纯 remote 的团队还是第一次, 是一种全新的尝试和挑战, 我也在不断的学习和适应当中,不知不觉两周过去了, 算下来每天的 Coding 时间大约在 2h - 3h 之间,PR Review 和 Design Review 大约在 1h 以内,和同事的会议平均每天 25min 左右,有较为成块的时间来进行系统学习和实验,也终于有了较多的时间给自己的儿子和女儿。
|
|
51
|
-
|
|
52
|
-
附上我的一个粗略的时间表.
|
|
53
|
-
|
|
54
|
-
**上午**
|
|
55
|
-
|
|
56
|
-
* 07:40 - 08:00 早上起床,完成洗簌.
|
|
57
|
-
* 08:00 - 08:40 带女儿出去吃早餐,然后送女儿去幼儿园.
|
|
58
|
-
* 08:40 - 09:00 去家门口咖啡店, 或者远一点的店找一个不错的位置,然后点一杯拿铁或者美式.
|
|
59
|
-
* 09:00 - 09:30 查看和回复 Slack 和邮件, 然后看一下今天的任务优先级,开始进入工作状态.
|
|
60
|
-
* 09:30 - 11:00 写代码 --> 写测试 --> Pull Request. 或者 Review Pull Request, Review Architecture Design.
|
|
61
|
-
* 11:00 - 11:30 和同事的会议一般都尽可能的安排在这个时间.
|
|
62
|
-
* 11:30 - 11:45 刷一下 GitHub Explore, HackerNews, 和 Reddit 的相关 Channels, 顺便 Twitter, 微博,v站划划水.
|
|
63
|
-
|
|
64
|
-
**中午**
|
|
65
|
-
|
|
66
|
-
* 11:45 - 12:30 如果在家门口的咖啡店就会回家和儿子父母吃午饭, 远的话就直接在店里解决午饭的问题.
|
|
67
|
-
* 12:30 - 13:20, 和儿子去球场运动或者在家里玩玩具,儿子作息和规律,玩一会他就会开始午睡.
|
|
68
|
-
* 13:20 - 13:30 回到咖啡店,一杯冰拿铁.
|
|
69
|
-
|
|
70
|
-
**下午**
|
|
71
|
-
|
|
72
|
-
* 13:30 - 14:00 写一道算法题, 偶尔会在 typing.io 上进行输入练习.这是工作日的 kata.
|
|
73
|
-
* 14:00 - 15:30 密集的代码编写,测试,重构的时间,然后发 Pull Request, 更新相关的文档.
|
|
74
|
-
* 15:30 - 16:20 去幼儿园接女儿,然后带她吃点东西,送回家,
|
|
75
|
-
* 16:30 - 17:30 在家工作, 主要是 Review 同事的PR Review 和 对自己的PR 进行必要的重构,最后在 Slack 总结发出当日状态的明天的安排.
|
|
76
|
-
* 17:30 - 18:40 送女儿去课外兴趣班,一般也会带着电脑和正在看的书. 偶尔也会进行 PR Review 或者看书.然后发现 iPad + 便携式的键盘非常适合在非工作场所写东西.
|
|
77
|
-
|
|
78
|
-
**晚上**
|
|
79
|
-
|
|
80
|
-
* 19:00 - 22:00 回家吃晚饭,给小宝贝们洗澡,和媳妇带他们在小区或者旁边的商场散步,或者在家陪他们玩电子设备或者数学游戏,然后讲故事带他们睡觉.
|
|
81
|
-
* 22:30 - 24:00 看 Slack 和邮件,回复紧急信息,然后写文字或者代码.
|
|
82
|
-
* 24:00 上床睡觉,时常带着耳机看美剧或者武林外传,听着听着就睡着了.
|