creght-cli 0.7.5 → 0.8.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/README.md +15 -112
- package/package.json +1 -20
- package/vendor/darwin-arm64/creght +0 -0
- package/vendor/darwin-x64/creght +0 -0
- package/vendor/linux-arm64/creght +0 -0
- package/vendor/linux-x64/creght +0 -0
- package/vendor/win32-arm64/creght.exe +0 -0
- package/vendor/win32-x64/creght.exe +0 -0
- package/vite/import-map.js +0 -55
- package/vite/index.d.ts +0 -28
- package/vite/index.js +0 -546
- package/vite/index.test.mjs +0 -47
- package/vite/package.json +0 -3
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Creght CLI is a thin local bridge for syncing site code between a local directory and Creght.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Creght remains responsible for cloud rendering, CMS, assets, and the preview environment. The CLI does not render sites locally; use `creght preview` to open the canonical remote preview.
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -180,54 +180,6 @@ generated/*
|
|
|
180
180
|
/scratch/
|
|
181
181
|
```
|
|
182
182
|
|
|
183
|
-
## Local Vite Preview
|
|
184
|
-
|
|
185
|
-
Creght projects pulled by the CLI usually do not have their own `package.json`
|
|
186
|
-
or `node_modules`. The local preview plugin therefore uses Vite only for local
|
|
187
|
-
file serving and TSX transpilation; third-party packages continue to resolve
|
|
188
|
-
through the Creght import map, matching the Web editor preview model. In
|
|
189
|
-
`creght dev`, the CLI serves the workspace directory, loads the platform import
|
|
190
|
-
map from server system info, and passes it to the Vite plugin; the plugin's
|
|
191
|
-
local map is only a fallback.
|
|
192
|
-
|
|
193
|
-
Install Vite in the local project folder:
|
|
194
|
-
|
|
195
|
-
```bash
|
|
196
|
-
cd ./mysite
|
|
197
|
-
npm init -y
|
|
198
|
-
npm install -D vite esbuild creght-cli
|
|
199
|
-
```
|
|
200
|
-
|
|
201
|
-
Create `vite.config.mjs`:
|
|
202
|
-
|
|
203
|
-
```js
|
|
204
|
-
import { defineConfig } from 'vite'
|
|
205
|
-
import creght from 'creght-cli/vite'
|
|
206
|
-
|
|
207
|
-
export default defineConfig({
|
|
208
|
-
plugins: [
|
|
209
|
-
creght({
|
|
210
|
-
apiHost: 'https://creght.cn',
|
|
211
|
-
projectId: '<project_id>',
|
|
212
|
-
// token: process.env.CREGHT_TOKEN,
|
|
213
|
-
}),
|
|
214
|
-
],
|
|
215
|
-
})
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
Run it:
|
|
219
|
-
|
|
220
|
-
```bash
|
|
221
|
-
npx vite --host 0.0.0.0
|
|
222
|
-
```
|
|
223
|
-
|
|
224
|
-
The plugin maps `/page/Index.tsx` to `/`, `/page/About.tsx` to `/about`, starts
|
|
225
|
-
from the platform import map, merges `creght.config.ts` import-map entries,
|
|
226
|
-
loads `/index.css` through the Tailwind browser runtime, proxies local `/api/*`
|
|
227
|
-
requests to `apiHost`, calls page `getServerSideProps()` in the browser for a
|
|
228
|
-
preview-only first render, and uses Vite HMR to re-import the current page
|
|
229
|
-
module after local file changes without a full page reload.
|
|
230
|
-
|
|
231
183
|
## Push Local Changes
|
|
232
184
|
|
|
233
185
|
Push the current local directory snapshot to Creght and exit:
|
|
@@ -288,57 +240,6 @@ content is backed up under `.creght/backup/<timestamp>-*/`.
|
|
|
288
240
|
`base_to_local_diff` / `base_to_remote_diff`, so agents can decide how to
|
|
289
241
|
resolve without extra round-trips.
|
|
290
242
|
|
|
291
|
-
## Local Web Editor Bidirectional Sync
|
|
292
|
-
|
|
293
|
-
Run local files and the online Creght editor against the same cloud realtime
|
|
294
|
-
files:
|
|
295
|
-
|
|
296
|
-
```bash
|
|
297
|
-
creght dev --site_id=<project_id>/<site_id> --dir=./mysite
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
For local backend or web development:
|
|
301
|
-
|
|
302
|
-
```bash
|
|
303
|
-
CREGHT_API_HOST=http://localhost:8433 creght dev --web=http://localhost:5173 --site_id=<project_id>/<site_id> --dir=./mysite
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
The command prints the online Web editor URL, pushes local file changes to
|
|
307
|
-
Creght, and listens to the existing WebSocket collaboration channel so editor
|
|
308
|
-
changes are written back to the local directory. MVP conflict handling is last
|
|
309
|
-
write wins.
|
|
310
|
-
|
|
311
|
-
`dev` also starts a local Vite preview by default:
|
|
312
|
-
|
|
313
|
-
```text
|
|
314
|
-
VITE v8.0.14 ready in 529 ms
|
|
315
|
-
➜ Local: http://localhost:5173/
|
|
316
|
-
Local Vite: started (preferred http://localhost:5173; use the Vite Local URL above)
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
Use `--preview-port` or `--preview-host` to change the preferred local preview
|
|
320
|
-
address. If that port is occupied, Vite uses its normal auto-port behavior and
|
|
321
|
-
prints the actual URL in the terminal:
|
|
322
|
-
|
|
323
|
-
```bash
|
|
324
|
-
creght dev --site_id=<project_id>/<site_id> --dir=./mysite --preview-port=5174
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
Disable the local preview when you only want file sync:
|
|
328
|
-
|
|
329
|
-
```bash
|
|
330
|
-
creght dev --site_id=<project_id>/<site_id> --dir=./mysite --no-preview
|
|
331
|
-
```
|
|
332
|
-
|
|
333
|
-
The preview uses the bundled `creght-cli/vite` plugin. If the site directory
|
|
334
|
-
has `node_modules/.bin/vite`, that local Vite is used; otherwise the CLI starts
|
|
335
|
-
a hidden temporary Vite runtime under `.creght/` and installs `vite` plus
|
|
336
|
-
`esbuild` there.
|
|
337
|
-
|
|
338
|
-
Local file changes are pushed through Vite HMR as a React root re-render. This
|
|
339
|
-
avoids a browser-level refresh, but it is not yet full React Fast Refresh and
|
|
340
|
-
does not guarantee component state preservation.
|
|
341
|
-
|
|
342
243
|
## Open Preview
|
|
343
244
|
|
|
344
245
|
Open the remote preview URL for a site in the browser:
|
|
@@ -428,10 +329,14 @@ Top-level `slug` and `sort` are optional; the `--slug` / `--sort` flags override
|
|
|
428
329
|
|
|
429
330
|
```bash
|
|
430
331
|
creght content create --site_id=<project_id>/<site_id> --collection=prompts --data=./content.json --slug=typography-v02
|
|
431
|
-
creght content update --site_id=<project_id>/<site_id> --collection=prompts --id=<content_id> --
|
|
332
|
+
creght content update --site_id=<project_id>/<site_id> --collection=prompts --id=<content_id> --sort=15
|
|
432
333
|
```
|
|
433
334
|
|
|
434
|
-
`
|
|
335
|
+
`update` applies a partial update, so `--data` is optional there — pass `--slug` / `--sort` alone to rename or reorder without re-submitting the body, as in the command above. `create` still requires `--data`.
|
|
336
|
+
|
|
337
|
+
`sort` controls the order editors see in the CMS list, bigger first. Omitting it lets `create` append the entry last and leaves `update`'s current value alone. Use `content update --sort` to reorder; deleting and recreating an entry changes its id, and site versions do not snapshot CMS content, so that cannot be undone.
|
|
338
|
+
|
|
339
|
+
One asymmetry worth knowing: the platform reads a zero `sort` on **create** as "auto-assign, append last", so a literal `0` cannot be created — `create --sort=0` appends. `update --sort=0` does store a real 0.
|
|
435
340
|
|
|
436
341
|
## Manage Forms
|
|
437
342
|
|
|
@@ -487,8 +392,10 @@ creght table record delete --site_id=<project_id>/<site_id> --table=appointments
|
|
|
487
392
|
|
|
488
393
|
`record update` sends a patch body to the backend. Existing fields are merged,
|
|
489
394
|
and a `null` field value removes that field. Both `create` and `update` accept
|
|
490
|
-
`--sort=<n
|
|
491
|
-
|
|
395
|
+
`--sort=<n>`; omitting the flag leaves `sort` out of the request instead of
|
|
396
|
+
zeroing it. Unlike content, a record's `sort` cannot be set to `0` — the platform
|
|
397
|
+
ignores a zero sort on record update, so `--sort=0` is rejected there rather than
|
|
398
|
+
silently doing nothing, and on `create` it means "append last".
|
|
492
399
|
|
|
493
400
|
## Func Backend Code As Files
|
|
494
401
|
|
|
@@ -502,8 +409,7 @@ The workflow is the same as for any site file:
|
|
|
502
409
|
|
|
503
410
|
1. Run `creght pull --site_id=<project_id>/<site_id> --dir=./mysite`.
|
|
504
411
|
2. Edit or create files under `./mysite/backend/func/`.
|
|
505
|
-
3. Run `creght push --site_id=<project_id>/<site_id> --dir=./mysite
|
|
506
|
-
`creght dev` running.
|
|
412
|
+
3. Run `creght push --site_id=<project_id>/<site_id> --dir=./mysite`.
|
|
507
413
|
|
|
508
414
|
Examples:
|
|
509
415
|
|
|
@@ -546,7 +452,7 @@ The output matches the Func HTTP response protocol: successful runs print
|
|
|
546
452
|
top-level `ok` execution wrapper.
|
|
547
453
|
|
|
548
454
|
There are no `creght func list/get/create/update/delete` commands. Manage Func
|
|
549
|
-
code by editing `backend/func` files and syncing them with pull/push
|
|
455
|
+
code by editing `backend/func` files and syncing them with pull/push
|
|
550
456
|
like any other site file; `func run` only runs sample input.
|
|
551
457
|
|
|
552
458
|
## Upload Assets
|
|
@@ -598,8 +504,7 @@ with three-way merge, push local files back to Creght, resolve conflicts, open
|
|
|
598
504
|
the remote preview, and publish a site.
|
|
599
505
|
|
|
600
506
|
The CLI commands still use the Creght backend and web app for the canonical
|
|
601
|
-
preview. The
|
|
602
|
-
not implement full production SSR.
|
|
507
|
+
preview. The CLI does not render sites locally.
|
|
603
508
|
|
|
604
509
|
```bash
|
|
605
510
|
creght login [--web=https://creght.cn]
|
|
@@ -608,7 +513,6 @@ creght project list
|
|
|
608
513
|
creght pull --site_id=<project_id>/<site_id> --dir=./mysite
|
|
609
514
|
creght push --site_id=<project_id>/<site_id> --dir=./mysite
|
|
610
515
|
creght resolve --list
|
|
611
|
-
creght dev --site_id=<project_id>/<site_id> --dir=./mysite [--web=https://creght.cn]
|
|
612
516
|
creght preview --site_id=<project_id>/<site_id>
|
|
613
517
|
creght publish --site_id=<project_id>/<site_id> [--note=<note>]
|
|
614
518
|
creght cms collections --site_id=<project_id>/<site_id>
|
|
@@ -632,14 +536,13 @@ Command meanings:
|
|
|
632
536
|
- `pull`: Download site files (including Func code under `backend/func/`) into a local workspace, three-way merging remote and local edits.
|
|
633
537
|
- `push`: Push local workspace changes to the remote site/project after a three-way conflict check.
|
|
634
538
|
- `resolve`: List files with conflict markers, or resolve one by keeping the local (`--ours`) or remote (`--theirs`) side.
|
|
635
|
-
- `dev`: Bidirectionally sync local files with cloud realtime files and the online Web editor.
|
|
636
539
|
- `preview`: Open the remote preview URL for a site in the browser.
|
|
637
540
|
- `publish`: Publish a site to make the current remote site version live.
|
|
638
541
|
- `cms`: Manage CMS collections.
|
|
639
542
|
- `content`: Manage CMS content entries.
|
|
640
543
|
- `form`: Manage forms and form submissions.
|
|
641
544
|
- `table`: Manage project JSON tables and records used by Func.
|
|
642
|
-
- `func`: Run project Func backend code with sample input. Func code itself is edited as `backend/func` site files and synced with pull/push
|
|
545
|
+
- `func`: Run project Func backend code with sample input. Func code itself is edited as `backend/func` site files and synced with pull/push.
|
|
643
546
|
- `upload`: Upload a local file as a Creght site asset and print its URL.
|
|
644
547
|
- `version`: Print the installed CLI version.
|
|
645
548
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "creght-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Creght CLI for syncing local site code with Creght.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://github.com/creght-dev/creght-cli#readme",
|
|
@@ -14,12 +14,6 @@
|
|
|
14
14
|
"bin": {
|
|
15
15
|
"creght": "bin/creght.js"
|
|
16
16
|
},
|
|
17
|
-
"exports": {
|
|
18
|
-
"./vite": {
|
|
19
|
-
"types": "./vite/index.d.ts",
|
|
20
|
-
"import": "./vite/index.js"
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
17
|
"scripts": {
|
|
24
18
|
"prepare:npm-binaries": "node scripts/prepare-npm-binaries.js",
|
|
25
19
|
"test:npm": "node scripts/install.js --check"
|
|
@@ -27,25 +21,12 @@
|
|
|
27
21
|
"files": [
|
|
28
22
|
"bin/",
|
|
29
23
|
"scripts/",
|
|
30
|
-
"vite/",
|
|
31
24
|
"vendor/",
|
|
32
25
|
"README.md"
|
|
33
26
|
],
|
|
34
27
|
"engines": {
|
|
35
28
|
"node": ">=18"
|
|
36
29
|
},
|
|
37
|
-
"peerDependencies": {
|
|
38
|
-
"esbuild": ">=0.20",
|
|
39
|
-
"vite": ">=5"
|
|
40
|
-
},
|
|
41
|
-
"peerDependenciesMeta": {
|
|
42
|
-
"esbuild": {
|
|
43
|
-
"optional": true
|
|
44
|
-
},
|
|
45
|
-
"vite": {
|
|
46
|
-
"optional": true
|
|
47
|
-
}
|
|
48
|
-
},
|
|
49
30
|
"os": [
|
|
50
31
|
"darwin",
|
|
51
32
|
"linux",
|
|
Binary file
|
package/vendor/darwin-x64/creght
CHANGED
|
Binary file
|
|
Binary file
|
package/vendor/linux-x64/creght
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/vite/import-map.js
DELETED
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
function mergeExternalDeps(externalValue, requiredDeps) {
|
|
2
|
-
try {
|
|
3
|
-
externalValue = decodeURIComponent(externalValue)
|
|
4
|
-
} catch {
|
|
5
|
-
// Keep the original value and continue merging invalid encoded external lists.
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const seen = new Set()
|
|
9
|
-
const deps = externalValue
|
|
10
|
-
.split(',')
|
|
11
|
-
.map((dep) => dep.trim())
|
|
12
|
-
.filter(Boolean)
|
|
13
|
-
.filter((dep) => {
|
|
14
|
-
if (seen.has(dep)) return false
|
|
15
|
-
seen.add(dep)
|
|
16
|
-
return true
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
for (const dep of requiredDeps) {
|
|
20
|
-
if (seen.has(dep)) continue
|
|
21
|
-
seen.add(dep)
|
|
22
|
-
deps.push(dep)
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
return deps.join(',')
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export function normalizeImportMapExternal(specifier, url) {
|
|
29
|
-
if (!/^https?:\/\//i.test(url)) return url
|
|
30
|
-
if (
|
|
31
|
-
specifier === 'react' ||
|
|
32
|
-
specifier.startsWith('react/') ||
|
|
33
|
-
specifier === 'react-dom' ||
|
|
34
|
-
specifier.startsWith('react-dom/')
|
|
35
|
-
) {
|
|
36
|
-
return url
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
const requiredDeps = ['react', 'react-dom']
|
|
40
|
-
const hashIndex = url.indexOf('#')
|
|
41
|
-
const beforeHash = hashIndex >= 0 ? url.slice(0, hashIndex) : url
|
|
42
|
-
const hash = hashIndex >= 0 ? url.slice(hashIndex) : ''
|
|
43
|
-
const hasPrefixSlash = specifier.endsWith('/') && beforeHash.endsWith('/')
|
|
44
|
-
const externalTarget = hasPrefixSlash ? beforeHash.slice(0, -1) : beforeHash
|
|
45
|
-
const externalSuffix = hasPrefixSlash ? '/' : ''
|
|
46
|
-
const externalMatch = externalTarget.match(/([?&])external=([^&#]*)/)
|
|
47
|
-
|
|
48
|
-
if (externalMatch && externalMatch.index !== undefined) {
|
|
49
|
-
const start = externalMatch.index + externalMatch[1].length + 'external='.length
|
|
50
|
-
const end = start + externalMatch[2].length
|
|
51
|
-
return `${externalTarget.slice(0, start)}${mergeExternalDeps(externalMatch[2], requiredDeps)}${externalTarget.slice(end)}${externalSuffix}${hash}`
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
return `${externalTarget}${hasPrefixSlash || externalTarget.includes('?') ? '&' : '?'}external=${requiredDeps.join(',')}${externalSuffix}${hash}`
|
|
55
|
-
}
|
package/vite/index.d.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import type { Plugin } from 'vite'
|
|
2
|
-
|
|
3
|
-
export type CreghtVitePluginOptions = {
|
|
4
|
-
/**
|
|
5
|
-
* Local Creght project root. Defaults to Vite's root.
|
|
6
|
-
*/
|
|
7
|
-
root?: string
|
|
8
|
-
/**
|
|
9
|
-
* Creght API host used by the local /api proxy at runtime.
|
|
10
|
-
*/
|
|
11
|
-
apiHost?: string
|
|
12
|
-
/**
|
|
13
|
-
* Project id for runtime CMS/form requests.
|
|
14
|
-
*/
|
|
15
|
-
projectId?: string
|
|
16
|
-
/**
|
|
17
|
-
* Optional CLI auth token. When set, local /api proxy sends it as Bearer.
|
|
18
|
-
*/
|
|
19
|
-
token?: string
|
|
20
|
-
/**
|
|
21
|
-
* Platform import map entries. `creght dev` fills this from server system info.
|
|
22
|
-
* Manually configured entries override the built-in fallback when no server map is provided.
|
|
23
|
-
*/
|
|
24
|
-
importMap?: Record<string, string>
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
export declare function creght(options?: CreghtVitePluginOptions): Plugin
|
|
28
|
-
export default creght
|
package/vite/index.js
DELETED
|
@@ -1,546 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs/promises'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import { transform as esbuildTransform } from 'esbuild'
|
|
4
|
-
import { normalizeImportMapExternal } from './import-map.js'
|
|
5
|
-
|
|
6
|
-
const modulePrefix = '/@creght/module'
|
|
7
|
-
const assetPrefix = '/@creght/asset'
|
|
8
|
-
const runtimePrefix = '/@creght/runtime'
|
|
9
|
-
const pageExts = ['.tsx', '.ts', '.jsx', '.js']
|
|
10
|
-
const sourceExts = new Set([...pageExts, '.css'])
|
|
11
|
-
|
|
12
|
-
const fallbackImportMap = {
|
|
13
|
-
react: 'https://esm.talizen.com/react@19.2.4?dev',
|
|
14
|
-
'react/': 'https://esm.talizen.com/react@19.2.4&dev/',
|
|
15
|
-
'react-dom': 'https://esm.talizen.com/react-dom@19.2.4?dev',
|
|
16
|
-
'react-dom/': 'https://esm.talizen.com/react-dom@19.2.4&dev/',
|
|
17
|
-
'react-dom/client': 'https://esm.talizen.com/react-dom@19.2.4/client?dev',
|
|
18
|
-
'class-variance-authority': 'https://esm.talizen.com/class-variance-authority@0.7.1',
|
|
19
|
-
clsx: 'https://esm.talizen.com/clsx@2.1.1',
|
|
20
|
-
'tailwind-merge': 'https://esm.talizen.com/tailwind-merge@3.5.0',
|
|
21
|
-
'@radix-ui/react-slot': 'https://esm.talizen.com/@radix-ui/react-slot@1.2.4',
|
|
22
|
-
'lucide-react': 'https://esm.talizen.com/lucide-react@0.577.0?dev&external=react,react-dom',
|
|
23
|
-
motion: 'https://esm.talizen.com/motion@12.38.0?dev',
|
|
24
|
-
'motion/react': 'https://esm.talizen.com/motion@12.38.0/react?dev&external=react,react-dom',
|
|
25
|
-
'framer-motion': 'https://esm.talizen.com/framer-motion@12.38.0?dev&external=react,react-dom',
|
|
26
|
-
three: 'https://esm.talizen.com/three@0.167.1',
|
|
27
|
-
'three/': 'https://esm.talizen.com/three@0.167.1/',
|
|
28
|
-
'@react-three/fiber': 'https://esm.talizen.com/@react-three/fiber@9.3.0?external=react,react-dom,three',
|
|
29
|
-
'@react-three/drei': 'https://esm.talizen.com/@react-three/drei@10.7.4?external=react,react-dom,three,@react-three',
|
|
30
|
-
talizen: 'https://esm.talizen.com/talizen@0.1.4',
|
|
31
|
-
'talizen/': 'https://esm.talizen.com/talizen@0.1.4/',
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const escapeHtml = (s) => String(s)
|
|
35
|
-
.replaceAll('&', '&')
|
|
36
|
-
.replaceAll('<', '<')
|
|
37
|
-
.replaceAll('>', '>')
|
|
38
|
-
.replaceAll('"', '"')
|
|
39
|
-
|
|
40
|
-
const jsonScript = (value) => JSON.stringify(value).replaceAll('<', '\\u003c')
|
|
41
|
-
|
|
42
|
-
const transformWithEsbuild = (source, filename, options) =>
|
|
43
|
-
esbuildTransform(source, { ...options, sourcefile: filename })
|
|
44
|
-
|
|
45
|
-
const isRelativeSpecifier = (specifier) =>
|
|
46
|
-
specifier.startsWith('./') || specifier.startsWith('../') || specifier.startsWith('/')
|
|
47
|
-
|
|
48
|
-
const contentTypeForPath = (file) => {
|
|
49
|
-
switch (path.extname(file).toLowerCase()) {
|
|
50
|
-
case '.css':
|
|
51
|
-
return 'text/css; charset=utf-8'
|
|
52
|
-
case '.js':
|
|
53
|
-
case '.mjs':
|
|
54
|
-
return 'text/javascript; charset=utf-8'
|
|
55
|
-
case '.json':
|
|
56
|
-
return 'application/json; charset=utf-8'
|
|
57
|
-
case '.svg':
|
|
58
|
-
return 'image/svg+xml'
|
|
59
|
-
case '.png':
|
|
60
|
-
return 'image/png'
|
|
61
|
-
case '.jpg':
|
|
62
|
-
case '.jpeg':
|
|
63
|
-
return 'image/jpeg'
|
|
64
|
-
case '.gif':
|
|
65
|
-
return 'image/gif'
|
|
66
|
-
case '.webp':
|
|
67
|
-
return 'image/webp'
|
|
68
|
-
case '.woff':
|
|
69
|
-
return 'font/woff'
|
|
70
|
-
case '.woff2':
|
|
71
|
-
return 'font/woff2'
|
|
72
|
-
default:
|
|
73
|
-
return 'application/octet-stream'
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
const normalizeProjectPath = (value) => {
|
|
78
|
-
const out = path.posix.normalize('/' + value.replaceAll(path.sep, '/').replace(/^\/+/, ''))
|
|
79
|
-
if (out.startsWith('/../')) {
|
|
80
|
-
throw new Error(`unsafe Creght path: ${value}`)
|
|
81
|
-
}
|
|
82
|
-
return out
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async function exists(file) {
|
|
86
|
-
try {
|
|
87
|
-
await fs.access(file)
|
|
88
|
-
return true
|
|
89
|
-
} catch {
|
|
90
|
-
return false
|
|
91
|
-
}
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
async function resolveFile(projectRoot, projectPath) {
|
|
95
|
-
const clean = normalizeProjectPath(projectPath)
|
|
96
|
-
const abs = path.join(projectRoot, clean.slice(1))
|
|
97
|
-
if (await exists(abs)) return { projectPath: clean, abs }
|
|
98
|
-
|
|
99
|
-
for (const ext of pageExts) {
|
|
100
|
-
if (await exists(abs + ext)) {
|
|
101
|
-
return { projectPath: clean + ext, abs: abs + ext }
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
for (const ext of pageExts) {
|
|
106
|
-
const indexPath = path.join(abs, 'Index' + ext)
|
|
107
|
-
if (await exists(indexPath)) {
|
|
108
|
-
return { projectPath: normalizeProjectPath(path.posix.join(clean, 'Index' + ext)), abs: indexPath }
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
throw new Error(`Creght module not found: ${projectPath}`)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
async function readSiteConfig(projectRoot) {
|
|
116
|
-
for (const name of ['creght.config.ts', 'creght.config.js', 'talizen.config.ts', 'talizen.config.js', 'folia.config.ts', 'folia.config.js']) {
|
|
117
|
-
const abs = path.join(projectRoot, name)
|
|
118
|
-
if (!(await exists(abs))) continue
|
|
119
|
-
|
|
120
|
-
try {
|
|
121
|
-
const source = await fs.readFile(abs, 'utf8')
|
|
122
|
-
const transformed = await transformWithEsbuild(source, abs, {
|
|
123
|
-
loader: name.endsWith('.ts') ? 'ts' : 'js',
|
|
124
|
-
format: 'cjs',
|
|
125
|
-
target: 'es2020',
|
|
126
|
-
})
|
|
127
|
-
const module = { exports: {} }
|
|
128
|
-
const require = (specifier) => {
|
|
129
|
-
if (specifier === 'creght' || specifier === 'creght/config' || specifier === 'talizen' || specifier === 'talizen/config') {
|
|
130
|
-
return { defineConfig: (config) => config }
|
|
131
|
-
}
|
|
132
|
-
if (specifier.startsWith('creght/')) return {}
|
|
133
|
-
if (specifier.startsWith('talizen/')) return {}
|
|
134
|
-
throw new Error(`[creght.config] unsupported import: ${specifier}`)
|
|
135
|
-
}
|
|
136
|
-
const fn = new Function('module', 'exports', 'require', 'defineConfig', transformed.code)
|
|
137
|
-
fn(module, module.exports, require, (config) => config)
|
|
138
|
-
const value = module.exports?.default ?? module.exports
|
|
139
|
-
return value && typeof value === 'object' ? value : {}
|
|
140
|
-
} catch (err) {
|
|
141
|
-
console.warn(`[creght vite] failed to evaluate ${name}:`, err)
|
|
142
|
-
return {}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return {}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
async function readIndexCss(projectRoot, config) {
|
|
150
|
-
if (typeof config.tailwindCss === 'string') return config.tailwindCss
|
|
151
|
-
|
|
152
|
-
const cssPath = path.join(projectRoot, 'index.css')
|
|
153
|
-
if (!(await exists(cssPath))) return ''
|
|
154
|
-
return fs.readFile(cssPath, 'utf8')
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
async function buildImportMap(projectRoot, options) {
|
|
158
|
-
const config = await readSiteConfig(projectRoot)
|
|
159
|
-
const userImports = config.importMap?.imports || {}
|
|
160
|
-
const imports = Object.keys(options.importMap || {}).length > 0
|
|
161
|
-
? { ...options.importMap }
|
|
162
|
-
: { ...fallbackImportMap }
|
|
163
|
-
|
|
164
|
-
for (const [specifier, url] of Object.entries(userImports)) {
|
|
165
|
-
imports[specifier] = normalizeImportMapExternal(specifier, String(url))
|
|
166
|
-
}
|
|
167
|
-
for (const [specifier, url] of Object.entries(options.importMap || {})) {
|
|
168
|
-
imports[specifier] = normalizeImportMapExternal(specifier, String(url))
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
return { config, imports }
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
async function listPages(projectRoot) {
|
|
175
|
-
const pageRoot = path.join(projectRoot, 'page')
|
|
176
|
-
if (!(await exists(pageRoot))) return []
|
|
177
|
-
|
|
178
|
-
const out = []
|
|
179
|
-
async function walk(dir) {
|
|
180
|
-
const entries = await fs.readdir(dir, { withFileTypes: true })
|
|
181
|
-
for (const entry of entries) {
|
|
182
|
-
const abs = path.join(dir, entry.name)
|
|
183
|
-
if (entry.isDirectory()) {
|
|
184
|
-
await walk(abs)
|
|
185
|
-
continue
|
|
186
|
-
}
|
|
187
|
-
const ext = path.extname(entry.name)
|
|
188
|
-
if (!pageExts.includes(ext)) continue
|
|
189
|
-
if (entry.name.includes('.canvas.')) continue
|
|
190
|
-
const rel = normalizeProjectPath(path.relative(projectRoot, abs))
|
|
191
|
-
out.push({ file: rel, route: routeFromPagePath(rel) })
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
|
-
await walk(pageRoot)
|
|
195
|
-
return out.sort((a, b) => a.route.localeCompare(b.route))
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
function routeFromPagePath(file) {
|
|
199
|
-
const withoutExt = file.replace(/^\/page\//, '').replace(/\.[^.]+$/, '')
|
|
200
|
-
if (withoutExt === 'Index') return '/'
|
|
201
|
-
return '/' + withoutExt
|
|
202
|
-
.replace(/\/Index$/, '')
|
|
203
|
-
.split('/')
|
|
204
|
-
.map((segment) => segment.startsWith('[') && segment.endsWith(']') ? `:${segment.slice(1, -1)}` : segment.toLowerCase())
|
|
205
|
-
.join('/')
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
function matchRoute(routes, pathname) {
|
|
209
|
-
const normalized = pathname !== '/' ? pathname.replace(/\/+$/, '') : '/'
|
|
210
|
-
const exact = routes.find((r) => r.route === normalized)
|
|
211
|
-
if (exact) return { ...exact, params: {} }
|
|
212
|
-
|
|
213
|
-
for (const route of routes) {
|
|
214
|
-
const routeParts = route.route.split('/').filter(Boolean)
|
|
215
|
-
const pathParts = normalized.split('/').filter(Boolean)
|
|
216
|
-
if (routeParts.length !== pathParts.length) continue
|
|
217
|
-
const params = {}
|
|
218
|
-
let ok = true
|
|
219
|
-
for (let i = 0; i < routeParts.length; i++) {
|
|
220
|
-
const part = routeParts[i]
|
|
221
|
-
if (part.startsWith(':')) {
|
|
222
|
-
params[part.slice(1)] = decodeURIComponent(pathParts[i])
|
|
223
|
-
continue
|
|
224
|
-
}
|
|
225
|
-
if (part !== pathParts[i].toLowerCase()) {
|
|
226
|
-
ok = false
|
|
227
|
-
break
|
|
228
|
-
}
|
|
229
|
-
}
|
|
230
|
-
if (ok) return { ...route, params }
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return { ...(routes.find((r) => r.route === '/') || routes[0]), params: {} }
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function rewriteModuleSpecifiers(code, importerPath) {
|
|
237
|
-
const rewrite = (specifier) => {
|
|
238
|
-
if (!isRelativeSpecifier(specifier)) return specifier
|
|
239
|
-
const [rawPath, rawQuery = ''] = specifier.split('?')
|
|
240
|
-
const importerDir = path.posix.dirname(importerPath)
|
|
241
|
-
const resolved = normalizeProjectPath(path.posix.join(importerDir, rawPath))
|
|
242
|
-
const target = rawQuery ? `${resolved}?${rawQuery}` : resolved
|
|
243
|
-
return `${modulePrefix}?path=${encodeURIComponent(target)}`
|
|
244
|
-
}
|
|
245
|
-
|
|
246
|
-
return code
|
|
247
|
-
.replace(/(from\s*["'])([^"']+)(["'])/g, (_, before, specifier, after) => `${before}${rewrite(specifier)}${after}`)
|
|
248
|
-
.replace(/(import\s*["'])([^"']+)(["'])/g, (_, before, specifier, after) => `${before}${rewrite(specifier)}${after}`)
|
|
249
|
-
.replace(/(import\s*\(\s*["'])([^"']+)(["']\s*\))/g, (_, before, specifier, after) => `${before}${rewrite(specifier)}${after}`)
|
|
250
|
-
}
|
|
251
|
-
|
|
252
|
-
async function transformProjectModule(projectRoot, projectPath) {
|
|
253
|
-
const [pathWithoutQuery, query = ''] = projectPath.split('?')
|
|
254
|
-
const { projectPath: resolvedProjectPath, abs } = await resolveFile(projectRoot, pathWithoutQuery)
|
|
255
|
-
const ext = path.extname(abs).toLowerCase()
|
|
256
|
-
|
|
257
|
-
if (query === 'raw') {
|
|
258
|
-
const source = await fs.readFile(abs, 'utf8')
|
|
259
|
-
return `export default ${JSON.stringify(source)};\n`
|
|
260
|
-
}
|
|
261
|
-
if (query === 'url') {
|
|
262
|
-
return `export default ${JSON.stringify(`${assetPrefix}?path=${encodeURIComponent(resolvedProjectPath)}`)};\n`
|
|
263
|
-
}
|
|
264
|
-
if (!sourceExts.has(ext)) {
|
|
265
|
-
return `export default ${JSON.stringify(`${assetPrefix}?path=${encodeURIComponent(resolvedProjectPath)}`)};\n`
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
const source = await fs.readFile(abs, 'utf8')
|
|
269
|
-
if (abs.endsWith('.css')) {
|
|
270
|
-
return `
|
|
271
|
-
const css = ${JSON.stringify(source)};
|
|
272
|
-
let style = document.querySelector('style[data-talizen-css-module="${resolvedProjectPath}"]');
|
|
273
|
-
if (!style) {
|
|
274
|
-
style = document.createElement('style');
|
|
275
|
-
style.dataset.talizenCssModule = ${JSON.stringify(resolvedProjectPath)};
|
|
276
|
-
document.head.appendChild(style);
|
|
277
|
-
}
|
|
278
|
-
style.textContent = css;
|
|
279
|
-
export default css;
|
|
280
|
-
`
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
const loader = abs.endsWith('.tsx') ? 'tsx' : abs.endsWith('.ts') ? 'ts' : abs.endsWith('.jsx') ? 'jsx' : 'js'
|
|
284
|
-
const result = await transformWithEsbuild(source, abs, {
|
|
285
|
-
loader,
|
|
286
|
-
jsx: 'automatic',
|
|
287
|
-
jsxDev: true,
|
|
288
|
-
sourcemap: 'inline',
|
|
289
|
-
target: 'es2020',
|
|
290
|
-
define: {
|
|
291
|
-
'process.env.NODE_ENV': '"development"',
|
|
292
|
-
'process.env.RENDER_ENV': '"design"',
|
|
293
|
-
'process.env.RENDER_MODE': '"design"',
|
|
294
|
-
},
|
|
295
|
-
})
|
|
296
|
-
|
|
297
|
-
return rewriteModuleSpecifiers(result.code, resolvedProjectPath)
|
|
298
|
-
}
|
|
299
|
-
|
|
300
|
-
function renderRuntimeScript(entryFile, params, options) {
|
|
301
|
-
const projectId = options.projectId || ''
|
|
302
|
-
const authHeaders = options.token ? { Authorization: `Bearer ${options.token}` } : {}
|
|
303
|
-
|
|
304
|
-
return `
|
|
305
|
-
import React from 'react';
|
|
306
|
-
import { createRoot } from 'react-dom/client';
|
|
307
|
-
import { createHotContext } from '/@vite/client';
|
|
308
|
-
|
|
309
|
-
const creghtRuntimeHeaders = ${jsonScript(authHeaders)};
|
|
310
|
-
const creghtRuntimeFetch = window.fetch.bind(window);
|
|
311
|
-
|
|
312
|
-
window.TalizenConfig = {
|
|
313
|
-
baseUrl: window.location.origin + '/api/u/v2/project/' + ${JSON.stringify(projectId)},
|
|
314
|
-
headers: creghtRuntimeHeaders,
|
|
315
|
-
fetch(input, init = {}) {
|
|
316
|
-
const headers = new Headers(init.headers || {});
|
|
317
|
-
for (const [key, value] of Object.entries(creghtRuntimeHeaders)) {
|
|
318
|
-
if (!headers.has(key)) headers.set(key, value);
|
|
319
|
-
}
|
|
320
|
-
return creghtRuntimeFetch(input, { ...init, headers });
|
|
321
|
-
},
|
|
322
|
-
};
|
|
323
|
-
|
|
324
|
-
const rootEl = document.getElementById('root');
|
|
325
|
-
const root = createRoot(rootEl);
|
|
326
|
-
let renderVersion = 0;
|
|
327
|
-
|
|
328
|
-
async function loadPageModule() {
|
|
329
|
-
return import(${JSON.stringify(`${modulePrefix}?path=${encodeURIComponent(entryFile)}`)} + '&t=' + Date.now());
|
|
330
|
-
}
|
|
331
|
-
|
|
332
|
-
async function renderPage() {
|
|
333
|
-
const version = ++renderVersion;
|
|
334
|
-
const pageModule = await loadPageModule();
|
|
335
|
-
if (version !== renderVersion) return;
|
|
336
|
-
|
|
337
|
-
const Page = pageModule.default || pageModule.App;
|
|
338
|
-
let props = {};
|
|
339
|
-
|
|
340
|
-
if (!Page) {
|
|
341
|
-
throw new Error('Creght page has no default export: ${entryFile}');
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
if (typeof pageModule.getServerSideProps === 'function') {
|
|
345
|
-
const result = await pageModule.getServerSideProps({
|
|
346
|
-
query: Object.fromEntries(new URLSearchParams(window.location.search)),
|
|
347
|
-
params: ${jsonScript(params)},
|
|
348
|
-
});
|
|
349
|
-
props = result && result.props ? result.props : {};
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
root.render(React.createElement(Page, props));
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
const hot = createHotContext(${JSON.stringify(`${runtimePrefix}?entry=${encodeURIComponent(entryFile)}`)});
|
|
356
|
-
|
|
357
|
-
await renderPage();
|
|
358
|
-
|
|
359
|
-
hot.on('creght:update', () => {
|
|
360
|
-
renderPage().catch((err) => {
|
|
361
|
-
console.error('[creght vite] hot update failed', err);
|
|
362
|
-
});
|
|
363
|
-
});
|
|
364
|
-
`
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
async function renderHtml(projectRoot, pathname, options) {
|
|
368
|
-
const routes = await listPages(projectRoot)
|
|
369
|
-
if (routes.length === 0) {
|
|
370
|
-
return `<!doctype html><div style="font:14px system-ui;padding:24px">No Creght pages found in <code>/page</code>.</div>`
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
const matched = matchRoute(routes, pathname)
|
|
374
|
-
const { config, imports } = await buildImportMap(projectRoot, options)
|
|
375
|
-
const indexCss = await readIndexCss(projectRoot, config)
|
|
376
|
-
const customCode = config.customCode || {}
|
|
377
|
-
|
|
378
|
-
return `<!doctype html>
|
|
379
|
-
<html lang="en">
|
|
380
|
-
<head>
|
|
381
|
-
<meta charset="UTF-8">
|
|
382
|
-
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
383
|
-
<title>${escapeHtml(matched.route === '/' ? 'Creght' : matched.route)}</title>
|
|
384
|
-
<script type="importmap">${jsonScript({ imports })}</script>
|
|
385
|
-
<script type="module" src="/@vite/client"></script>
|
|
386
|
-
<style type="text/tailwindcss">${indexCss}</style>
|
|
387
|
-
<script type="module" src="https://esm.talizen.com/@tailwindcss/browser@4"></script>
|
|
388
|
-
${customCode.head || ''}
|
|
389
|
-
</head>
|
|
390
|
-
<body>
|
|
391
|
-
${customCode.bodyStart || ''}
|
|
392
|
-
<div id="root"></div>
|
|
393
|
-
<script type="module" src="${runtimePrefix}?entry=${encodeURIComponent(matched.file)}¶ms=${encodeURIComponent(JSON.stringify(matched.params))}&t=${Date.now()}"></script>
|
|
394
|
-
${customCode.bodyEnd || customCode.body || ''}
|
|
395
|
-
</body>
|
|
396
|
-
</html>`
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
export function creght(options = {}) {
|
|
400
|
-
let projectRoot = ''
|
|
401
|
-
const apiHost = (options.apiHost || 'https://creght.cn').replace(/\/+$/, '')
|
|
402
|
-
|
|
403
|
-
return {
|
|
404
|
-
name: 'creght-local-preview',
|
|
405
|
-
enforce: 'pre',
|
|
406
|
-
configResolved(config) {
|
|
407
|
-
projectRoot = path.resolve(options.root || config.root)
|
|
408
|
-
},
|
|
409
|
-
configureServer(server) {
|
|
410
|
-
const hmrTimers = new Map()
|
|
411
|
-
const sendCreghtUpdate = (file) => {
|
|
412
|
-
if (!file.startsWith(projectRoot)) return
|
|
413
|
-
|
|
414
|
-
const projectPath = normalizeProjectPath(path.relative(projectRoot, file))
|
|
415
|
-
const existing = hmrTimers.get(projectPath)
|
|
416
|
-
if (existing) clearTimeout(existing)
|
|
417
|
-
|
|
418
|
-
hmrTimers.set(projectPath, setTimeout(() => {
|
|
419
|
-
hmrTimers.delete(projectPath)
|
|
420
|
-
server.ws.send({
|
|
421
|
-
type: 'custom',
|
|
422
|
-
event: 'creght:update',
|
|
423
|
-
data: {
|
|
424
|
-
file: projectPath,
|
|
425
|
-
time: Date.now(),
|
|
426
|
-
},
|
|
427
|
-
})
|
|
428
|
-
}, 80))
|
|
429
|
-
}
|
|
430
|
-
|
|
431
|
-
server.watcher.add(path.join(projectRoot, '**/*'))
|
|
432
|
-
server.watcher.on('change', sendCreghtUpdate)
|
|
433
|
-
server.watcher.on('add', sendCreghtUpdate)
|
|
434
|
-
server.watcher.on('unlink', sendCreghtUpdate)
|
|
435
|
-
|
|
436
|
-
server.middlewares.use(async (req, res, next) => {
|
|
437
|
-
try {
|
|
438
|
-
const url = new URL(req.url || '/', 'http://localhost')
|
|
439
|
-
|
|
440
|
-
if (url.pathname.startsWith('/api/')) {
|
|
441
|
-
const headers = new Headers()
|
|
442
|
-
for (const [key, value] of Object.entries(req.headers)) {
|
|
443
|
-
if (Array.isArray(value)) {
|
|
444
|
-
headers.set(key, value.join(', '))
|
|
445
|
-
} else if (value != null) {
|
|
446
|
-
headers.set(key, value)
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
headers.set('host', new URL(apiHost).host)
|
|
450
|
-
if (options.token) {
|
|
451
|
-
headers.delete('cookie')
|
|
452
|
-
headers.set('authorization', `Bearer ${options.token}`)
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
const method = req.method || 'GET'
|
|
456
|
-
const body = method === 'GET' || method === 'HEAD' ? undefined : req
|
|
457
|
-
const upstream = await fetch(apiHost + url.pathname + url.search, {
|
|
458
|
-
method,
|
|
459
|
-
headers,
|
|
460
|
-
body,
|
|
461
|
-
// Required by Node fetch when the request body is a stream.
|
|
462
|
-
duplex: body ? 'half' : undefined,
|
|
463
|
-
})
|
|
464
|
-
|
|
465
|
-
res.statusCode = upstream.status
|
|
466
|
-
upstream.headers.forEach((value, key) => {
|
|
467
|
-
const lowerKey = key.toLowerCase()
|
|
468
|
-
if (lowerKey === 'content-encoding') return
|
|
469
|
-
if (lowerKey === 'content-length') return
|
|
470
|
-
if (lowerKey === 'transfer-encoding') return
|
|
471
|
-
if (lowerKey === 'connection') return
|
|
472
|
-
res.setHeader(key, value)
|
|
473
|
-
})
|
|
474
|
-
const data = Buffer.from(await upstream.arrayBuffer())
|
|
475
|
-
res.end(data)
|
|
476
|
-
return
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
if (url.pathname === modulePrefix) {
|
|
480
|
-
const projectPath = url.searchParams.get('path')
|
|
481
|
-
if (!projectPath) {
|
|
482
|
-
res.statusCode = 400
|
|
483
|
-
res.end('missing path')
|
|
484
|
-
return
|
|
485
|
-
}
|
|
486
|
-
const code = await transformProjectModule(projectRoot, projectPath)
|
|
487
|
-
res.setHeader('Content-Type', 'text/javascript; charset=utf-8')
|
|
488
|
-
res.end(code)
|
|
489
|
-
return
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
if (url.pathname === runtimePrefix) {
|
|
493
|
-
const entry = url.searchParams.get('entry')
|
|
494
|
-
const rawParams = url.searchParams.get('params') || '{}'
|
|
495
|
-
if (!entry) {
|
|
496
|
-
res.statusCode = 400
|
|
497
|
-
res.end('missing entry')
|
|
498
|
-
return
|
|
499
|
-
}
|
|
500
|
-
let params = {}
|
|
501
|
-
try {
|
|
502
|
-
params = JSON.parse(rawParams)
|
|
503
|
-
} catch {
|
|
504
|
-
params = {}
|
|
505
|
-
}
|
|
506
|
-
res.setHeader('Content-Type', 'text/javascript; charset=utf-8')
|
|
507
|
-
res.end(renderRuntimeScript(entry, params, options))
|
|
508
|
-
return
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
if (url.pathname === assetPrefix) {
|
|
512
|
-
const projectPath = url.searchParams.get('path')
|
|
513
|
-
if (!projectPath) {
|
|
514
|
-
res.statusCode = 400
|
|
515
|
-
res.end('missing path')
|
|
516
|
-
return
|
|
517
|
-
}
|
|
518
|
-
const { abs } = await resolveFile(projectRoot, projectPath)
|
|
519
|
-
res.setHeader('Content-Type', contentTypeForPath(abs))
|
|
520
|
-
res.end(await fs.readFile(abs))
|
|
521
|
-
return
|
|
522
|
-
}
|
|
523
|
-
|
|
524
|
-
if (req.method !== 'GET') {
|
|
525
|
-
next()
|
|
526
|
-
return
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
const accept = req.headers.accept || ''
|
|
530
|
-
if (!accept.includes('text/html')) {
|
|
531
|
-
next()
|
|
532
|
-
return
|
|
533
|
-
}
|
|
534
|
-
|
|
535
|
-
const html = await renderHtml(projectRoot, url.pathname, options)
|
|
536
|
-
res.setHeader('Content-Type', 'text/html; charset=utf-8')
|
|
537
|
-
res.end(html)
|
|
538
|
-
} catch (err) {
|
|
539
|
-
next(err)
|
|
540
|
-
}
|
|
541
|
-
})
|
|
542
|
-
},
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
export default creght
|
package/vite/index.test.mjs
DELETED
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict'
|
|
2
|
-
import { describe, it } from 'node:test'
|
|
3
|
-
|
|
4
|
-
import { normalizeImportMapExternal } from './import-map.js'
|
|
5
|
-
|
|
6
|
-
describe('normalizeImportMapExternal', () => {
|
|
7
|
-
it('adds react and react-dom externals to regular import map entries', () => {
|
|
8
|
-
assert.equal(
|
|
9
|
-
normalizeImportMapExternal('framer-motion', 'https://esm.talizen.com/framer-motion'),
|
|
10
|
-
'https://esm.talizen.com/framer-motion?external=react,react-dom',
|
|
11
|
-
)
|
|
12
|
-
})
|
|
13
|
-
|
|
14
|
-
it('merges missing externals without dropping existing entries', () => {
|
|
15
|
-
assert.equal(
|
|
16
|
-
normalizeImportMapExternal(
|
|
17
|
-
'@react-three/drei',
|
|
18
|
-
'https://esm.talizen.com/@react-three/drei?external=three,react,@react-three/fiber',
|
|
19
|
-
),
|
|
20
|
-
'https://esm.talizen.com/@react-three/drei?external=three,react,@react-three/fiber,react-dom',
|
|
21
|
-
)
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
it('inserts externals before the trailing slash for prefix import map entries', () => {
|
|
25
|
-
assert.equal(
|
|
26
|
-
normalizeImportMapExternal('talizen/', 'https://esm.talizen.com/talizen@0.1.4/'),
|
|
27
|
-
'https://esm.talizen.com/talizen@0.1.4&external=react,react-dom/',
|
|
28
|
-
)
|
|
29
|
-
})
|
|
30
|
-
|
|
31
|
-
it('merges externals before the trailing slash for prefix entries', () => {
|
|
32
|
-
assert.equal(
|
|
33
|
-
normalizeImportMapExternal(
|
|
34
|
-
'@kobalte/core/',
|
|
35
|
-
'https://esm.talizen.com/@kobalte/core&external=react/',
|
|
36
|
-
),
|
|
37
|
-
'https://esm.talizen.com/@kobalte/core&external=react,react-dom/',
|
|
38
|
-
)
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
it('does not modify host React runtime specifiers', () => {
|
|
42
|
-
assert.equal(
|
|
43
|
-
normalizeImportMapExternal('react-dom/client', 'https://esm.talizen.com/react-dom@19/client?dev'),
|
|
44
|
-
'https://esm.talizen.com/react-dom@19/client?dev',
|
|
45
|
-
)
|
|
46
|
-
})
|
|
47
|
-
})
|
package/vite/package.json
DELETED