create-jant 0.3.27 → 0.3.29
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/dist/index.js +50 -95
- package/package.json +2 -3
- package/template/README.md +66 -235
- package/template/_github/workflows/deploy.yml +36 -14
- package/template/_gitignore +0 -15
- package/template/index.js +3 -0
- package/template/package.json +4 -24
- package/template/wrangler.toml +34 -27
- package/template/.prettierrc +0 -1
- package/template/node_modules/.bin/tsc +0 -21
- package/template/node_modules/.bin/tsserver +0 -21
- package/template/node_modules/.bin/vite +0 -21
- package/template/node_modules/.bin/wrangler +0 -21
- package/template/node_modules/.bin/wrangler2 +0 -21
- package/template/pnpm-workspace.yaml +0 -7
- package/template/scripts/export-demo.mjs +0 -84
- package/template/scripts/export-seed.mjs +0 -89
- package/template/scripts/reset-demo.sql +0 -20
- package/template/scripts/reset-local.sql +0 -25
- package/template/scripts/reset-password.mjs +0 -20
- package/template/scripts/seed-demo.sql +0 -187
- package/template/scripts/seed-local.sql +0 -216
- package/template/src/client.ts +0 -11
- package/template/src/index.ts +0 -15
- package/template/src/style.css +0 -8
- package/template/tsconfig.app.json +0 -29
- package/template/tsconfig.json +0 -7
- package/template/tsconfig.node.json +0 -20
- package/template/vite.config.ts +0 -215
- package/template/wrangler.demo.toml +0 -25
- /package/template/{_env.example → .dev.vars.example} +0 -0
package/dist/index.js
CHANGED
|
@@ -9,8 +9,8 @@ import path from "path";
|
|
|
9
9
|
import { fileURLToPath } from "url";
|
|
10
10
|
var __filename = fileURLToPath(import.meta.url);
|
|
11
11
|
var __dirname = path.dirname(__filename);
|
|
12
|
-
var CORE_VERSION = "0.3.
|
|
13
|
-
var TEMPLATE_DIR = fs.existsSync(path.resolve(__dirname, "../template")) ? path.resolve(__dirname, "../template") : path.resolve(__dirname, "../../../
|
|
12
|
+
var CORE_VERSION = "0.3.29";
|
|
13
|
+
var TEMPLATE_DIR = fs.existsSync(path.resolve(__dirname, "../template")) ? path.resolve(__dirname, "../template") : path.resolve(__dirname, "../../../sites/demo");
|
|
14
14
|
function isValidProjectName(name) {
|
|
15
15
|
return /^[a-z0-9]([a-z0-9-]*[a-z0-9])?$/.test(name);
|
|
16
16
|
}
|
|
@@ -40,9 +40,6 @@ function detectPackageManager() {
|
|
|
40
40
|
function formatRunCmd(pm, script) {
|
|
41
41
|
return pm === "npm" ? `npm run ${script}` : `${pm} ${script}`;
|
|
42
42
|
}
|
|
43
|
-
function formatAddCmd(pm, pkg) {
|
|
44
|
-
return pm === "npm" ? `npm install ${pkg}` : `${pm} add ${pkg}`;
|
|
45
|
-
}
|
|
46
43
|
function runCommand(cmd, cwd) {
|
|
47
44
|
try {
|
|
48
45
|
execSync(cmd, { stdio: "ignore", cwd });
|
|
@@ -51,58 +48,56 @@ function runCommand(cmd, cwd) {
|
|
|
51
48
|
return false;
|
|
52
49
|
}
|
|
53
50
|
}
|
|
54
|
-
function
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
)
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
51
|
+
function processAnnotations(content, vars) {
|
|
52
|
+
const lines = content.split("\n");
|
|
53
|
+
const result = [];
|
|
54
|
+
let removing = false;
|
|
55
|
+
for (const line of lines) {
|
|
56
|
+
if (line.trim() === "# @create-jant: @remove-start") {
|
|
57
|
+
removing = true;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (line.trim() === "# @create-jant: @remove-end") {
|
|
61
|
+
removing = false;
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
if (removing) continue;
|
|
65
|
+
if (line.includes("# @create-jant: @remove")) {
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const replaceMatch = line.match(/^(.+?)\s*#\s*@create-jant:\s*"(.*)"$/);
|
|
69
|
+
if (replaceMatch) {
|
|
70
|
+
const prefix = replaceMatch[1];
|
|
71
|
+
const newValue = replaceMatch[2];
|
|
72
|
+
const interpolated = newValue.replace(
|
|
67
73
|
/\$\{(\w+)\}/g,
|
|
68
|
-
(
|
|
74
|
+
(_, key) => vars[key] ?? ""
|
|
69
75
|
);
|
|
70
|
-
|
|
76
|
+
const valueMatch = prefix.match(/^(\s*\S+\s*=\s*)"[^"]*"(.*)$/);
|
|
77
|
+
if (valueMatch) {
|
|
78
|
+
result.push(`${valueMatch[1]}"${interpolated}"${valueMatch[2]}`);
|
|
79
|
+
} else {
|
|
80
|
+
result.push(prefix);
|
|
81
|
+
}
|
|
82
|
+
continue;
|
|
71
83
|
}
|
|
72
|
-
|
|
73
|
-
|
|
84
|
+
result.push(line);
|
|
85
|
+
}
|
|
86
|
+
return result.join("\n");
|
|
74
87
|
}
|
|
75
88
|
async function copyTemplate(config) {
|
|
76
89
|
const { projectName, targetDir, packageManager } = config;
|
|
77
90
|
await fs.copy(TEMPLATE_DIR, targetDir, {
|
|
78
91
|
filter: (src) => {
|
|
79
92
|
const basename = path.basename(src);
|
|
80
|
-
if (basename.startsWith(".DS_Store")) return false;
|
|
81
93
|
if (basename === "node_modules") return false;
|
|
82
94
|
if (basename === ".wrangler") return false;
|
|
83
|
-
if (basename === ".swc") return false;
|
|
84
95
|
if (basename === ".dev.vars") return false;
|
|
85
|
-
if (basename === "pnpm-lock.yaml") return false;
|
|
86
|
-
if (basename === "yarn.lock") return false;
|
|
87
|
-
if (basename === "package-lock.json") return false;
|
|
88
|
-
if (basename === "bun.lockb") return false;
|
|
89
|
-
if (basename === "pnpm-workspace.yaml") return false;
|
|
90
|
-
if (basename === "dist") return false;
|
|
91
|
-
if (basename === "wrangler.demo.toml") return false;
|
|
92
|
-
if (basename === "reset-demo.sql") return false;
|
|
93
|
-
if (basename === "seed-demo.sql") return false;
|
|
94
|
-
if (basename === "reset-local.sql") return false;
|
|
95
|
-
if (basename === "seed-local.sql") return false;
|
|
96
|
-
if (basename === "export-demo.mjs") return false;
|
|
97
|
-
if (basename === "export-seed.mjs") return false;
|
|
98
96
|
return true;
|
|
99
97
|
}
|
|
100
98
|
});
|
|
101
|
-
const secretsExampleFile = ".dev.vars.example";
|
|
102
|
-
const secretsFile = ".dev.vars";
|
|
103
99
|
const renames = [
|
|
104
100
|
["_gitignore", ".gitignore"],
|
|
105
|
-
["_env.example", secretsExampleFile],
|
|
106
101
|
["_github", ".github"]
|
|
107
102
|
];
|
|
108
103
|
for (const [from, to] of renames) {
|
|
@@ -119,17 +114,14 @@ async function copyTemplate(config) {
|
|
|
119
114
|
if (pkg.dependencies?.["@jant/core"] === "workspace:*") {
|
|
120
115
|
pkg.dependencies["@jant/core"] = `^${CORE_VERSION}`;
|
|
121
116
|
}
|
|
122
|
-
|
|
123
|
-
if (packageManager !== "pnpm") {
|
|
117
|
+
if (packageManager !== "pnpm" && pkg.scripts) {
|
|
124
118
|
delete pkg.packageManager;
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
);
|
|
132
|
-
}
|
|
119
|
+
for (const [key, value] of Object.entries(pkg.scripts)) {
|
|
120
|
+
if (typeof value === "string") {
|
|
121
|
+
pkg.scripts[key] = value.replace(
|
|
122
|
+
/pnpm run (\S+)/g,
|
|
123
|
+
(_, script) => formatRunCmd(packageManager, script)
|
|
124
|
+
);
|
|
133
125
|
}
|
|
134
126
|
}
|
|
135
127
|
}
|
|
@@ -138,7 +130,10 @@ async function copyTemplate(config) {
|
|
|
138
130
|
const wranglerPath = path.join(targetDir, "wrangler.toml");
|
|
139
131
|
if (await fs.pathExists(wranglerPath)) {
|
|
140
132
|
let content = await fs.readFile(wranglerPath, "utf-8");
|
|
141
|
-
content =
|
|
133
|
+
content = processAnnotations(content, { name: projectName });
|
|
134
|
+
if (config.s3) {
|
|
135
|
+
content = content.replace(/\n\[\[r2_buckets\]\][^[]*/s, "\n");
|
|
136
|
+
}
|
|
142
137
|
await fs.writeFile(wranglerPath, content, "utf-8");
|
|
143
138
|
}
|
|
144
139
|
const authSecret = generateAuthSecret();
|
|
@@ -147,19 +142,6 @@ async function copyTemplate(config) {
|
|
|
147
142
|
AUTH_SECRET=${authSecret}
|
|
148
143
|
`;
|
|
149
144
|
if (config.s3) {
|
|
150
|
-
if (await fs.pathExists(wranglerPath)) {
|
|
151
|
-
let wContent = await fs.readFile(wranglerPath, "utf-8");
|
|
152
|
-
wContent = wContent.replace(
|
|
153
|
-
/^# STORAGE_DRIVER = "s3"/m,
|
|
154
|
-
'STORAGE_DRIVER = "s3"'
|
|
155
|
-
);
|
|
156
|
-
wContent = wContent.replace(/^# S3_ENDPOINT = /m, "S3_ENDPOINT = ");
|
|
157
|
-
wContent = wContent.replace(/^# S3_BUCKET = /m, "S3_BUCKET = ");
|
|
158
|
-
wContent = wContent.replace(/^# S3_REGION = /m, "S3_REGION = ");
|
|
159
|
-
wContent = wContent.replace(/^# S3_PUBLIC_URL = /m, "S3_PUBLIC_URL = ");
|
|
160
|
-
wContent = wContent.replace(/\n\[\[r2_buckets\]\][^[]*/s, "\n");
|
|
161
|
-
await fs.writeFile(wranglerPath, wContent, "utf-8");
|
|
162
|
-
}
|
|
163
145
|
devVarsContent += `
|
|
164
146
|
# S3-compatible storage credentials
|
|
165
147
|
S3_ACCESS_KEY_ID=
|
|
@@ -167,37 +149,10 @@ S3_SECRET_ACCESS_KEY=
|
|
|
167
149
|
`;
|
|
168
150
|
}
|
|
169
151
|
await fs.writeFile(
|
|
170
|
-
path.join(targetDir,
|
|
152
|
+
path.join(targetDir, ".dev.vars"),
|
|
171
153
|
devVarsContent,
|
|
172
154
|
"utf-8"
|
|
173
155
|
);
|
|
174
|
-
const viteConfigPath = path.join(targetDir, "vite.config.ts");
|
|
175
|
-
if (await fs.pathExists(viteConfigPath)) {
|
|
176
|
-
let content = await fs.readFile(viteConfigPath, "utf-8");
|
|
177
|
-
content = processMarkers(content, {});
|
|
178
|
-
await fs.writeFile(viteConfigPath, content, "utf-8");
|
|
179
|
-
}
|
|
180
|
-
const readmePath = path.join(targetDir, "README.md");
|
|
181
|
-
if (packageManager !== "npm" && await fs.pathExists(readmePath)) {
|
|
182
|
-
let readme = await fs.readFile(readmePath, "utf-8");
|
|
183
|
-
readme = readme.replace(
|
|
184
|
-
/npm install (\S+)/g,
|
|
185
|
-
(_, pkg) => formatAddCmd(packageManager, pkg)
|
|
186
|
-
);
|
|
187
|
-
readme = readme.replace(/npm install/g, `${packageManager} install`);
|
|
188
|
-
readme = readme.replace(
|
|
189
|
-
/npm run (\S+)/g,
|
|
190
|
-
(_, script) => formatRunCmd(packageManager, script)
|
|
191
|
-
);
|
|
192
|
-
readme = readme.replace(/npm create/g, `${packageManager} create`);
|
|
193
|
-
await fs.writeFile(readmePath, readme, "utf-8");
|
|
194
|
-
}
|
|
195
|
-
if (packageManager === "pnpm") {
|
|
196
|
-
const wsSource = path.join(TEMPLATE_DIR, "pnpm-workspace.yaml");
|
|
197
|
-
if (await fs.pathExists(wsSource)) {
|
|
198
|
-
await fs.copy(wsSource, path.join(targetDir, "pnpm-workspace.yaml"));
|
|
199
|
-
}
|
|
200
|
-
}
|
|
201
156
|
}
|
|
202
157
|
async function main() {
|
|
203
158
|
console.log();
|
|
@@ -209,12 +164,12 @@ async function main() {
|
|
|
209
164
|
if (args[0]) {
|
|
210
165
|
projectName = args[0];
|
|
211
166
|
} else if (opts.yes) {
|
|
212
|
-
projectName = "jant-site";
|
|
167
|
+
projectName = "my-jant-site";
|
|
213
168
|
} else {
|
|
214
169
|
const result = await p.text({
|
|
215
170
|
message: "What is your project name?",
|
|
216
|
-
placeholder: "jant-site",
|
|
217
|
-
defaultValue: "jant-site",
|
|
171
|
+
placeholder: "my-jant-site",
|
|
172
|
+
defaultValue: "my-jant-site",
|
|
218
173
|
validate: (value) => {
|
|
219
174
|
if (!value) return "Project name is required";
|
|
220
175
|
const sanitized = toValidProjectName(value);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-jant",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.29",
|
|
4
4
|
"description": "Create a new Jant project",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -53,8 +53,7 @@
|
|
|
53
53
|
"build": "tsup src/index.ts --format esm --clean --outDir dist",
|
|
54
54
|
"dev": "tsup src/index.ts --format esm --watch",
|
|
55
55
|
"typecheck": "tsc --noEmit",
|
|
56
|
-
"copy-template": "rm -rf template &&
|
|
57
|
-
"prepare-template": "node scripts/prepare-template.js",
|
|
56
|
+
"copy-template": "rm -rf template && rsync -a --exclude node_modules --exclude .wrangler --exclude .dev.vars --exclude scripts ../../sites/demo/ template/ && mv template/.gitignore template/_gitignore && mv template/.github template/_github",
|
|
58
57
|
"inject-version": "node -e \"const fs=require('fs');const v=require('../core/package.json').version;const f='dist/index.js';fs.writeFileSync(f,fs.readFileSync(f,'utf8').replace('__JANT_CORE_VERSION__',v))\"",
|
|
59
58
|
"test-template": "node scripts/test-template.js"
|
|
60
59
|
}
|
package/template/README.md
CHANGED
|
@@ -1,46 +1,14 @@
|
|
|
1
|
-
# Jant
|
|
1
|
+
# Jant
|
|
2
2
|
|
|
3
|
-
A personal
|
|
3
|
+
A personal microblogging system — self-hosted, single-author, and stripped of all social mechanics. Runs on Cloudflare Workers.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Quick Start
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
### One-Click Deploy
|
|
8
8
|
|
|
9
9
|
[](https://deploy.workers.cloudflare.com/?url=https://github.com/jant-me/jant-starter)
|
|
10
10
|
|
|
11
|
-
###
|
|
12
|
-
|
|
13
|
-
| Field | What to do |
|
|
14
|
-
| -------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
15
|
-
| **Git account** | Select your GitHub account. A new repo will be created for you. |
|
|
16
|
-
| **D1 database** | Keep "Create new". The default name is fine. |
|
|
17
|
-
| **Database location hint** | Pick a region close to you (optional, Cloudflare auto-selects). |
|
|
18
|
-
| **R2 bucket** | Keep "Create new". The default name is fine. Used for media uploads. |
|
|
19
|
-
| **AUTH_SECRET** | Used for login session encryption. Keep the pre-filled value or generate your own with `openssl rand -base64 32`. |
|
|
20
|
-
| **SITE_URL** | Change this to your production URL (e.g. `https://my-blog.example.com`). If you don't have a custom domain yet, leave it empty — you can set it later in the Cloudflare dashboard after you know your `*.workers.dev` URL. |
|
|
21
|
-
|
|
22
|
-
### After deploy
|
|
23
|
-
|
|
24
|
-
1. Visit your site at the URL shown in the Cloudflare dashboard (e.g. `https://<project>.<account>.workers.dev`)
|
|
25
|
-
2. Go to `/dash` to set up your admin account
|
|
26
|
-
3. If you set `SITE_URL` to a custom domain, add it in: Cloudflare dashboard → Workers & Pages → your worker → Settings → Domains & Routes → Add Custom Domain
|
|
27
|
-
4. If you left `SITE_URL` empty, set it to your `*.workers.dev` URL: Cloudflare dashboard → Workers & Pages → your worker → Settings → Variables and Secrets
|
|
28
|
-
|
|
29
|
-
### Develop locally
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
# Clone the repo that was created for you
|
|
33
|
-
git clone git@github.com:<your-username>/<your-repo>.git
|
|
34
|
-
cd <your-repo>
|
|
35
|
-
npm install
|
|
36
|
-
npm run dev
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Visit http://localhost:9019. Changes pushed to `main` will auto-deploy.
|
|
40
|
-
|
|
41
|
-
## Option B: Create with CLI
|
|
42
|
-
|
|
43
|
-
Set up a new project locally, then deploy manually:
|
|
11
|
+
### CLI
|
|
44
12
|
|
|
45
13
|
```bash
|
|
46
14
|
npm create jant my-site
|
|
@@ -48,240 +16,103 @@ cd my-site
|
|
|
48
16
|
npm run dev
|
|
49
17
|
```
|
|
50
18
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
### Deploy to Cloudflare
|
|
54
|
-
|
|
55
|
-
#### 1. Prerequisites
|
|
56
|
-
|
|
57
|
-
Install [Wrangler CLI](https://developers.cloudflare.com/workers/wrangler/install-and-update/) and log in:
|
|
58
|
-
|
|
59
|
-
```bash
|
|
60
|
-
wrangler login
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
#### 2. Create D1 Database
|
|
19
|
+
### Manual Deploy
|
|
64
20
|
|
|
65
|
-
|
|
21
|
+
1. **Create a D1 database:**
|
|
66
22
|
|
|
67
|
-
```bash
|
|
68
|
-
wrangler d1 create
|
|
69
|
-
|
|
70
|
-
```
|
|
71
|
-
|
|
72
|
-
#### 3. Update Configuration
|
|
73
|
-
|
|
74
|
-
Edit `wrangler.toml`:
|
|
75
|
-
|
|
76
|
-
- Replace `database_id = "local"` with the ID from step 2
|
|
77
|
-
- Set `SITE_URL` to your production URL (e.g. `https://example.com`)
|
|
78
|
-
|
|
79
|
-
> R2 bucket is automatically created on first deploy — no manual setup needed.
|
|
80
|
-
>
|
|
81
|
-
> **Note:** Changing `database_id` resets your local development database (local data is stored per database ID). If you've already started local development, you'll need to go through the setup wizard again to create your admin account.
|
|
82
|
-
|
|
83
|
-
#### 4. Set Production Secrets
|
|
84
|
-
|
|
85
|
-
Generate a production secret and save it somewhere safe (you'll need it again for CI):
|
|
86
|
-
|
|
87
|
-
```bash
|
|
88
|
-
# Generate a secret
|
|
89
|
-
openssl rand -base64 32
|
|
90
|
-
|
|
91
|
-
# Set it in Cloudflare
|
|
92
|
-
wrangler secret put AUTH_SECRET
|
|
93
|
-
# Paste the generated value when prompted
|
|
94
|
-
```
|
|
95
|
-
|
|
96
|
-
> **Important:** This is separate from the `AUTH_SECRET` in `.dev.vars` (which is for local development only). Do not change the production secret after your site is live — it will invalidate all sessions. If you get locked out, use `npm run reset-password` to generate a password reset link.
|
|
97
|
-
|
|
98
|
-
#### 5. Deploy
|
|
99
|
-
|
|
100
|
-
```bash
|
|
101
|
-
# Apply database migrations and deploy
|
|
102
|
-
npm run deploy
|
|
103
|
-
```
|
|
23
|
+
```bash
|
|
24
|
+
npx wrangler d1 create my-site-db
|
|
25
|
+
```
|
|
104
26
|
|
|
105
|
-
|
|
27
|
+
2. **Update `wrangler.toml`** with the `database_id` from step 1 and set your `SITE_URL`.
|
|
106
28
|
|
|
107
|
-
|
|
29
|
+
3. **Set production secrets:**
|
|
108
30
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
31
|
+
```bash
|
|
32
|
+
npx wrangler secret put AUTH_SECRET
|
|
33
|
+
```
|
|
112
34
|
|
|
113
|
-
|
|
35
|
+
4. **Deploy:**
|
|
114
36
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
#### 1. Push to GitHub
|
|
120
|
-
|
|
121
|
-
Create a new repository on [GitHub](https://github.com/new), then commit and push your project:
|
|
122
|
-
|
|
123
|
-
```bash
|
|
124
|
-
git add -A
|
|
125
|
-
git commit -m "Initial setup"
|
|
126
|
-
git remote add origin git@github.com:<your-username>/<your-repo>.git
|
|
127
|
-
git push -u origin main
|
|
128
|
-
```
|
|
129
|
-
|
|
130
|
-
#### 2. Create API Token
|
|
131
|
-
|
|
132
|
-
1. Go to [Cloudflare API Tokens](https://dash.cloudflare.com/profile/api-tokens)
|
|
133
|
-
2. Click **Create Token** → **Use template** next to **Edit Cloudflare Workers**
|
|
134
|
-
3. **Add D1 permission** (not in template by default):
|
|
135
|
-
- Click **+ Add more** → **Account** → **D1** → **Edit**
|
|
136
|
-
|
|
137
|
-
Your permissions should include:
|
|
138
|
-
|
|
139
|
-
| Scope | Permission | Access |
|
|
140
|
-
| ------- | ------------------ | ----------------------------- |
|
|
141
|
-
| Account | Workers Scripts | Edit |
|
|
142
|
-
| Account | Workers R2 Storage | Edit |
|
|
143
|
-
| Account | **D1** | **Edit** ← Must add manually! |
|
|
144
|
-
| Zone | Workers Routes | Edit |
|
|
145
|
-
|
|
146
|
-
4. Set **Account Resources** → **Include** → your account
|
|
147
|
-
5. Set **Zone Resources** → **Include** → **All zones from an account** → your account
|
|
148
|
-
6. **Create Token** and copy it
|
|
149
|
-
|
|
150
|
-
#### 3. Add GitHub Secrets
|
|
151
|
-
|
|
152
|
-
Go to your repo → **Settings** → **Secrets and variables** → **Actions**:
|
|
153
|
-
|
|
154
|
-
| Secret Name | Value |
|
|
155
|
-
| --------------- | ------------------------------------------------------------------------ |
|
|
156
|
-
| `CF_API_TOKEN` | API token from above |
|
|
157
|
-
| `CF_ACCOUNT_ID` | Your Cloudflare Account ID (found in dashboard URL or `wrangler whoami`) |
|
|
158
|
-
|
|
159
|
-
#### 4. Enable Auto-Deploy
|
|
160
|
-
|
|
161
|
-
Uncomment the push trigger in `.github/workflows/deploy.yml`:
|
|
162
|
-
|
|
163
|
-
```yaml
|
|
164
|
-
on:
|
|
165
|
-
push:
|
|
166
|
-
branches:
|
|
167
|
-
- main
|
|
168
|
-
workflow_dispatch:
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
Now every push to `main` will auto-deploy.
|
|
172
|
-
|
|
173
|
-
#### Using Environments (Optional)
|
|
174
|
-
|
|
175
|
-
For separate staging/production, update `.github/workflows/deploy.yml`:
|
|
176
|
-
|
|
177
|
-
```yaml
|
|
178
|
-
jobs:
|
|
179
|
-
deploy:
|
|
180
|
-
uses: jant-me/jant/.github/workflows/deploy.yml@main
|
|
181
|
-
with:
|
|
182
|
-
environment: production # Uses [env.production] in wrangler.toml
|
|
183
|
-
secrets:
|
|
184
|
-
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
|
|
185
|
-
CF_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
|
186
|
-
```
|
|
37
|
+
```bash
|
|
38
|
+
npm run deploy
|
|
39
|
+
```
|
|
187
40
|
|
|
188
41
|
## Commands
|
|
189
42
|
|
|
190
|
-
| Command
|
|
191
|
-
|
|
|
192
|
-
| `npm run dev`
|
|
193
|
-
| `npm run
|
|
194
|
-
| `npm run deploy` | Migrate, build, and deploy |
|
|
195
|
-
| `npm run preview` | Preview production build |
|
|
196
|
-
| `npm run typecheck` | Run TypeScript checks |
|
|
197
|
-
| `npm run db:migrate:remote` | Apply database migrations (remote) |
|
|
43
|
+
| Command | Description |
|
|
44
|
+
| ---------------- | ------------------------------------------- |
|
|
45
|
+
| `npm run dev` | Start local dev server (applies migrations) |
|
|
46
|
+
| `npm run deploy` | Deploy to Cloudflare (applies migrations) |
|
|
198
47
|
|
|
199
48
|
## Environment Variables
|
|
200
49
|
|
|
201
|
-
|
|
202
|
-
| ------------- | ----------------------------------------- | ---------------- |
|
|
203
|
-
| `AUTH_SECRET` | Secret key for authentication (32+ chars) | `.dev.vars` file |
|
|
204
|
-
| `SITE_URL` | Your site's public URL | `wrangler.toml` |
|
|
50
|
+
Configuration is set in `wrangler.toml` and `.dev.vars`. See [Configuration](https://github.com/jant-me/jant/blob/main/docs/configuration.md) for the full reference.
|
|
205
51
|
|
|
206
|
-
|
|
52
|
+
**Required:**
|
|
207
53
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
54
|
+
| Variable | Where | Description |
|
|
55
|
+
| ------------- | --------------- | ---------------------------------- |
|
|
56
|
+
| `SITE_URL` | `wrangler.toml` | Your site's public URL |
|
|
57
|
+
| `AUTH_SECRET` | `.dev.vars` | Session encryption key (32+ chars) |
|
|
211
58
|
|
|
212
|
-
|
|
59
|
+
**Optional (in `wrangler.toml`):**
|
|
213
60
|
|
|
214
|
-
|
|
61
|
+
| Variable | Description |
|
|
62
|
+
| --------------------- | ----------------------------------------- |
|
|
63
|
+
| `SITE_NAME` | Display name (also settable in dashboard) |
|
|
64
|
+
| `SITE_DESCRIPTION` | Meta description / RSS subtitle |
|
|
65
|
+
| `SITE_LANGUAGE` | Language code (`en`, `zh`, etc.) |
|
|
66
|
+
| `R2_PUBLIC_URL` | Public URL for R2 media bucket |
|
|
67
|
+
| `IMAGE_TRANSFORM_URL` | Cloudflare Image Transformations URL |
|
|
215
68
|
|
|
216
|
-
|
|
69
|
+
## GitHub Actions CI/CD
|
|
217
70
|
|
|
218
|
-
|
|
71
|
+
The included workflow (`.github/workflows/deploy.yml`) deploys on every push to `main`.
|
|
219
72
|
|
|
220
|
-
|
|
73
|
+
**Setup:**
|
|
221
74
|
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
75
|
+
1. Add these **repository secrets** in Settings > Secrets and variables > Actions:
|
|
76
|
+
- `CF_API_TOKEN` — Cloudflare API token with Workers, D1, and R2 permissions
|
|
77
|
+
- `CF_ACCOUNT_ID` — your Cloudflare account ID
|
|
78
|
+
2. Set your production `AUTH_SECRET`:
|
|
79
|
+
```bash
|
|
80
|
+
npx wrangler secret put AUTH_SECRET
|
|
81
|
+
```
|
|
82
|
+
3. Push to `main` — the workflow handles migrations and deployment.
|
|
230
83
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
Target specific elements with stable data attributes:
|
|
84
|
+
## Customization
|
|
234
85
|
|
|
235
|
-
|
|
236
|
-
/* Style only note-format posts */
|
|
237
|
-
[data-format="note"] {
|
|
238
|
-
border-left: 3px solid var(--primary);
|
|
239
|
-
}
|
|
86
|
+
### CSS Tokens
|
|
240
87
|
|
|
241
|
-
|
|
242
|
-
[data-page="home"] {
|
|
243
|
-
background: var(--muted);
|
|
244
|
-
}
|
|
88
|
+
Customize colors through the dashboard (Settings > Appearance) or by overriding CSS variables. See [Theming](https://github.com/jant-me/jant/blob/main/docs/theming.md).
|
|
245
89
|
|
|
246
|
-
|
|
247
|
-
body:not([data-authenticated]) .compose-prompt {
|
|
248
|
-
display: none;
|
|
249
|
-
}
|
|
250
|
-
```
|
|
90
|
+
### Data Attributes
|
|
251
91
|
|
|
252
|
-
|
|
92
|
+
Target specific elements for styling with stable data attributes:
|
|
253
93
|
|
|
254
|
-
|
|
94
|
+
| Attribute | Purpose |
|
|
95
|
+
| ---------------- | ----------------------------- |
|
|
96
|
+
| `data-page` | Page type identifier |
|
|
97
|
+
| `data-post` | Post marker |
|
|
98
|
+
| `data-format` | Post format (note/link/quote) |
|
|
99
|
+
| `data-post-body` | Post body content |
|
|
255
100
|
|
|
256
|
-
|
|
257
|
-
import { createApp } from "@jant/core";
|
|
101
|
+
### Code-Level
|
|
258
102
|
|
|
259
|
-
|
|
260
|
-
cssVariables: {
|
|
261
|
-
"--site-width": "720px",
|
|
262
|
-
"--card-radius": "0.5rem",
|
|
263
|
-
},
|
|
264
|
-
});
|
|
265
|
-
```
|
|
103
|
+
For deeper changes, fork the project and modify `@jant/core` directly.
|
|
266
104
|
|
|
267
105
|
## Updating
|
|
268
106
|
|
|
269
107
|
```bash
|
|
270
|
-
|
|
271
|
-
npm install @jant/core@latest
|
|
272
|
-
|
|
273
|
-
# Start dev server (auto-applies migrations locally)
|
|
274
|
-
npm run dev
|
|
275
|
-
|
|
276
|
-
# Deploy (includes remote migrations)
|
|
108
|
+
npm update @jant/core
|
|
277
109
|
npm run deploy
|
|
278
110
|
```
|
|
279
111
|
|
|
280
|
-
|
|
281
|
-
>
|
|
282
|
-
> **Dev dependencies** (vite, wrangler, tailwindcss, etc.) may also need updating. Compare your `devDependencies` with the [latest template](https://github.com/jant-me/jant/blob/main/templates/jant-site/package.json) and update if needed.
|
|
112
|
+
Check the [changelog](https://github.com/jant-me/jant/releases) for breaking changes before updating.
|
|
283
113
|
|
|
284
114
|
## Documentation
|
|
285
115
|
|
|
286
|
-
- [
|
|
287
|
-
- [
|
|
116
|
+
- [Configuration](https://github.com/jant-me/jant/blob/main/docs/configuration.md)
|
|
117
|
+
- [Theming](https://github.com/jant-me/jant/blob/main/docs/theming.md)
|
|
118
|
+
- [GitHub](https://github.com/jant-me/jant)
|
|
@@ -1,25 +1,47 @@
|
|
|
1
|
-
# Deploy to Cloudflare Workers
|
|
2
|
-
# Documentation: https://jant.me/docs/deployment
|
|
1
|
+
# Deploy your Jant site to Cloudflare Workers.
|
|
3
2
|
#
|
|
4
3
|
# Prerequisites:
|
|
5
|
-
#
|
|
6
|
-
#
|
|
4
|
+
# 1. Create a D1 database: npx wrangler d1 create <name>
|
|
5
|
+
# 2. Update wrangler.toml with the database_id
|
|
6
|
+
# 3. Add repository secrets: CF_API_TOKEN, CF_ACCOUNT_ID
|
|
7
|
+
# 4. Set production secret: npx wrangler secret put AUTH_SECRET
|
|
7
8
|
#
|
|
8
|
-
#
|
|
9
|
-
# `wrangler secret put` and persist across deployments.
|
|
9
|
+
# Full setup guide: https://github.com/jant-me/jant
|
|
10
10
|
|
|
11
11
|
name: Deploy
|
|
12
12
|
|
|
13
13
|
on:
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# - main
|
|
14
|
+
push:
|
|
15
|
+
branches:
|
|
16
|
+
- main
|
|
18
17
|
workflow_dispatch:
|
|
19
18
|
|
|
20
19
|
jobs:
|
|
21
20
|
deploy:
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
name: Deploy
|
|
22
|
+
runs-on: ubuntu-latest
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- name: Checkout
|
|
26
|
+
uses: actions/checkout@v4
|
|
27
|
+
|
|
28
|
+
- name: Setup Node.js
|
|
29
|
+
uses: actions/setup-node@v4
|
|
30
|
+
with:
|
|
31
|
+
node-version: "24"
|
|
32
|
+
|
|
33
|
+
- name: Install dependencies
|
|
34
|
+
run: npm ci
|
|
35
|
+
|
|
36
|
+
- name: Run migrations
|
|
37
|
+
run: npx wrangler d1 migrations apply DB --remote
|
|
38
|
+
env:
|
|
39
|
+
CLOUDFLARE_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
|
|
40
|
+
CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CF_ACCOUNT_ID }}
|
|
41
|
+
|
|
42
|
+
- name: Deploy to Cloudflare Workers
|
|
43
|
+
uses: cloudflare/wrangler-action@v3
|
|
44
|
+
with:
|
|
45
|
+
apiToken: ${{ secrets.CF_API_TOKEN }}
|
|
46
|
+
accountId: ${{ secrets.CF_ACCOUNT_ID }}
|
|
47
|
+
command: deploy
|