@maiyunnet/kebab 9.3.4 → 9.3.6
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/doc/kebab-rag.md +90 -42
- package/index.d.ts +1 -1
- package/index.js +1 -1
- package/lib/core.d.ts +8 -0
- package/lib/core.js +54 -3
- package/lib/text.js +7 -1
- package/package.json +14 -14
- package/sys/master.js +76 -13
- package/www/example/stc/view/react-router.page.d.ts +4 -10
- package/www/example/stc/view/react-router.page.js +5 -7
- package/www/example/stc/view/react-router.page.tsx +8 -35
package/doc/kebab-rag.md
CHANGED
|
@@ -1360,7 +1360,7 @@ index/variables/VER.md
|
|
|
1360
1360
|
|
|
1361
1361
|
# Variable: VER
|
|
1362
1362
|
|
|
1363
|
-
> `const` **VER**: `"9.3.
|
|
1363
|
+
> `const` **VER**: `"9.3.6"` = `'9.3.6'`
|
|
1364
1364
|
|
|
1365
1365
|
Defined in: [index.ts:10](https://github.com/maiyunnet/kebab/blob/master/index.ts#L10)
|
|
1366
1366
|
|
|
@@ -3258,7 +3258,7 @@ lib/core/functions/clone.md
|
|
|
3258
3258
|
|
|
3259
3259
|
> **clone**\<`T`\>(`obj`): `T`
|
|
3260
3260
|
|
|
3261
|
-
Defined in: [lib/core.ts:
|
|
3261
|
+
Defined in: [lib/core.ts:1060](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L1060)
|
|
3262
3262
|
|
|
3263
3263
|
完整的克隆一份数组/对象
|
|
3264
3264
|
|
|
@@ -3322,7 +3322,7 @@ lib/core/functions/debug.md
|
|
|
3322
3322
|
|
|
3323
3323
|
> **debug**(`message?`, ...`optionalParams`): `void`
|
|
3324
3324
|
|
|
3325
|
-
Defined in: [lib/core.ts:
|
|
3325
|
+
Defined in: [lib/core.ts:1094](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L1094)
|
|
3326
3326
|
|
|
3327
3327
|
打印调试信息,线上环境不会打印
|
|
3328
3328
|
|
|
@@ -3357,7 +3357,7 @@ lib/core/functions/display.md
|
|
|
3357
3357
|
|
|
3358
3358
|
> **display**(`message?`, ...`optionalParams`): `void`
|
|
3359
3359
|
|
|
3360
|
-
Defined in: [lib/core.ts:
|
|
3360
|
+
Defined in: [lib/core.ts:1107](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L1107)
|
|
3361
3361
|
|
|
3362
3362
|
向控制台直接显示内容,一般情况下禁止使用
|
|
3363
3363
|
|
|
@@ -3462,7 +3462,7 @@ lib/core/functions/getLog.md
|
|
|
3462
3462
|
|
|
3463
3463
|
> **getLog**(`opt`): `Promise`\<`false` \| `string`[][] \| `null`\>
|
|
3464
3464
|
|
|
3465
|
-
Defined in: [lib/core.ts:
|
|
3465
|
+
Defined in: [lib/core.ts:967](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L967)
|
|
3466
3466
|
|
|
3467
3467
|
获取日志内容为一个数组
|
|
3468
3468
|
|
|
@@ -3568,7 +3568,7 @@ lib/core/functions/loadEnv.md
|
|
|
3568
3568
|
|
|
3569
3569
|
> **loadEnv**(`dir`): `Promise`\<`void`\>
|
|
3570
3570
|
|
|
3571
|
-
Defined in: [lib/core.ts:
|
|
3571
|
+
Defined in: [lib/core.ts:1159](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L1159)
|
|
3572
3572
|
|
|
3573
3573
|
加载 .env 文件到 process.env,若文件不存在则跳过
|
|
3574
3574
|
|
|
@@ -3597,7 +3597,7 @@ lib/core/functions/log.md
|
|
|
3597
3597
|
|
|
3598
3598
|
> **log**(`opt`, `msg`, `fend?`): `void`
|
|
3599
3599
|
|
|
3600
|
-
Defined in: [lib/core.ts:
|
|
3600
|
+
Defined in: [lib/core.ts:861](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L861)
|
|
3601
3601
|
|
|
3602
3602
|
写入文件日志
|
|
3603
3603
|
|
|
@@ -3638,7 +3638,7 @@ lib/core/functions/ls.md
|
|
|
3638
3638
|
|
|
3639
3639
|
> **ls**(`opt`): `Promise`\<`object`[]\>
|
|
3640
3640
|
|
|
3641
|
-
Defined in: [lib/core.ts:
|
|
3641
|
+
Defined in: [lib/core.ts:1021](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L1021)
|
|
3642
3642
|
|
|
3643
3643
|
获取目录内文件/文件夹列表
|
|
3644
3644
|
|
|
@@ -3964,7 +3964,7 @@ lib/core/functions/removeGlobal.md
|
|
|
3964
3964
|
|
|
3965
3965
|
> **removeGlobal**(`key`, `hosts?`): `Promise`\<`string`[]\>
|
|
3966
3966
|
|
|
3967
|
-
Defined in: [lib/core.ts:
|
|
3967
|
+
Defined in: [lib/core.ts:736](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L736)
|
|
3968
3968
|
|
|
3969
3969
|
移除某个跨线程/跨内网服务器全局变量
|
|
3970
3970
|
|
|
@@ -3999,7 +3999,7 @@ lib/core/functions/resolveEnvVars.md
|
|
|
3999
3999
|
|
|
4000
4000
|
> **resolveEnvVars**(`obj`): `void`
|
|
4001
4001
|
|
|
4002
|
-
Defined in: [lib/core.ts:
|
|
4002
|
+
Defined in: [lib/core.ts:1189](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L1189)
|
|
4003
4003
|
|
|
4004
4004
|
将配置对象中的 ${ENV_VAR} 占位符替换为 process.env 的值
|
|
4005
4005
|
|
|
@@ -4028,7 +4028,7 @@ lib/core/functions/sendNpm.md
|
|
|
4028
4028
|
|
|
4029
4029
|
> **sendNpm**(`path`, `hosts?`): `Promise`\<`string`[]\>
|
|
4030
4030
|
|
|
4031
|
-
Defined in: [lib/core.ts:
|
|
4031
|
+
Defined in: [lib/core.ts:649](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L649)
|
|
4032
4032
|
|
|
4033
4033
|
向本机或局域网 RPC 发送 npm install 操作
|
|
4034
4034
|
|
|
@@ -4091,6 +4091,53 @@ PM2 操作类型
|
|
|
4091
4091
|
|
|
4092
4092
|
`Promise`\<`string`[]\>
|
|
4093
4093
|
|
|
4094
|
+
lib/core/functions/sendProject.md
|
|
4095
|
+
---
|
|
4096
|
+
|
|
4097
|
+
[**Documents for @maiyunnet/kebab**](../../../index.md)
|
|
4098
|
+
|
|
4099
|
+
***
|
|
4100
|
+
|
|
4101
|
+
[Documents for @maiyunnet/kebab](../../../index.md) / [lib/core](../index.md) / sendProject
|
|
4102
|
+
|
|
4103
|
+
# Function: sendProject()
|
|
4104
|
+
|
|
4105
|
+
> **sendProject**(`path`, `key`, `value`, `hosts?`): `Promise`\<`string`[]\>
|
|
4106
|
+
|
|
4107
|
+
Defined in: [lib/core.ts:805](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L805)
|
|
4108
|
+
|
|
4109
|
+
向本机或局域网 RPC 发送项目配置更新操作
|
|
4110
|
+
|
|
4111
|
+
## Parameters
|
|
4112
|
+
|
|
4113
|
+
### path
|
|
4114
|
+
|
|
4115
|
+
`string`
|
|
4116
|
+
|
|
4117
|
+
项目路径,相对 Kebab 根
|
|
4118
|
+
|
|
4119
|
+
### key
|
|
4120
|
+
|
|
4121
|
+
`string`
|
|
4122
|
+
|
|
4123
|
+
要更新的键名(目前仅支持 staticVer)
|
|
4124
|
+
|
|
4125
|
+
### value
|
|
4126
|
+
|
|
4127
|
+
`string`
|
|
4128
|
+
|
|
4129
|
+
要更新的值
|
|
4130
|
+
|
|
4131
|
+
### hosts?
|
|
4132
|
+
|
|
4133
|
+
`string`[] \| `"config"`
|
|
4134
|
+
|
|
4135
|
+
局域网列表
|
|
4136
|
+
|
|
4137
|
+
## Returns
|
|
4138
|
+
|
|
4139
|
+
`Promise`\<`string`[]\>
|
|
4140
|
+
|
|
4094
4141
|
lib/core/functions/sendReload.md
|
|
4095
4142
|
---
|
|
4096
4143
|
|
|
@@ -4207,7 +4254,7 @@ lib/core/functions/setGlobal.md
|
|
|
4207
4254
|
|
|
4208
4255
|
> **setGlobal**(`key`, `data`, `hosts?`): `Promise`\<`string`[]\>
|
|
4209
4256
|
|
|
4210
|
-
Defined in: [lib/core.ts:
|
|
4257
|
+
Defined in: [lib/core.ts:695](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L695)
|
|
4211
4258
|
|
|
4212
4259
|
设置跨线程/指定的局域网主机的全局变量
|
|
4213
4260
|
|
|
@@ -4306,7 +4353,7 @@ lib/core/functions/updateCode.md
|
|
|
4306
4353
|
|
|
4307
4354
|
> **updateCode**(`sourcePath`, `path`, `hosts?`, `config?`, `strict?`): `Promise`\<`Record`\<`string`, \{ `result`: `boolean`; `return`: `string`; \}\>\>
|
|
4308
4355
|
|
|
4309
|
-
Defined in: [lib/core.ts:
|
|
4356
|
+
Defined in: [lib/core.ts:748](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L748)
|
|
4310
4357
|
|
|
4311
4358
|
上传并覆盖代码文件,config.json、kebab.json、.js.map、.ts, .gitignore 不会被覆盖和新创建
|
|
4312
4359
|
|
|
@@ -4359,7 +4406,7 @@ lib/core/functions/writeEventStreamHead.md
|
|
|
4359
4406
|
|
|
4360
4407
|
> **writeEventStreamHead**(`res`): `void`
|
|
4361
4408
|
|
|
4362
|
-
Defined in: [lib/core.ts:
|
|
4409
|
+
Defined in: [lib/core.ts:1129](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L1129)
|
|
4363
4410
|
|
|
4364
4411
|
## Parameters
|
|
4365
4412
|
|
|
@@ -4384,7 +4431,7 @@ lib/core/functions/writeHead.md
|
|
|
4384
4431
|
|
|
4385
4432
|
> **writeHead**(`res`, `statusCode`, `headers?`): `void`
|
|
4386
4433
|
|
|
4387
|
-
Defined in: [lib/core.ts:
|
|
4434
|
+
Defined in: [lib/core.ts:1118](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L1118)
|
|
4388
4435
|
|
|
4389
4436
|
让 res 发送头部(前提是头部没有被发送才能调用本方法
|
|
4390
4437
|
|
|
@@ -4425,7 +4472,7 @@ lib/core/functions/write.md
|
|
|
4425
4472
|
|
|
4426
4473
|
> **write**(`res`, `data`): `void`
|
|
4427
4474
|
|
|
4428
|
-
Defined in: [lib/core.ts:
|
|
4475
|
+
Defined in: [lib/core.ts:1141](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L1141)
|
|
4429
4476
|
|
|
4430
4477
|
向 res 发送数据
|
|
4431
4478
|
|
|
@@ -4509,6 +4556,7 @@ lib/core/index.md
|
|
|
4509
4556
|
- [resolveEnvVars](functions/resolveEnvVars.md)
|
|
4510
4557
|
- [sendNpm](functions/sendNpm.md)
|
|
4511
4558
|
- [sendPm2](functions/sendPm2.md)
|
|
4559
|
+
- [sendProject](functions/sendProject.md)
|
|
4512
4560
|
- [sendReload](functions/sendReload.md)
|
|
4513
4561
|
- [sendRestart](functions/sendRestart.md)
|
|
4514
4562
|
- [setCookie](functions/setCookie.md)
|
|
@@ -4594,7 +4642,7 @@ lib/core/interfaces/ILogOptions.md
|
|
|
4594
4642
|
|
|
4595
4643
|
# Interface: ILogOptions
|
|
4596
4644
|
|
|
4597
|
-
Defined in: [lib/core.ts:
|
|
4645
|
+
Defined in: [lib/core.ts:844](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L844)
|
|
4598
4646
|
|
|
4599
4647
|
log 设置的选项
|
|
4600
4648
|
|
|
@@ -4604,7 +4652,7 @@ log 设置的选项
|
|
|
4604
4652
|
|
|
4605
4653
|
> `optional` **cookie?**: `Record`\<`string`, `string`\>
|
|
4606
4654
|
|
|
4607
|
-
Defined in: [lib/core.ts:
|
|
4655
|
+
Defined in: [lib/core.ts:850](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L850)
|
|
4608
4656
|
|
|
4609
4657
|
***
|
|
4610
4658
|
|
|
@@ -4612,7 +4660,7 @@ Defined in: [lib/core.ts:796](https://github.com/maiyunnet/kebab/blob/master/lib
|
|
|
4612
4660
|
|
|
4613
4661
|
> `optional` **get?**: `Record`\<`string`, `any`\>
|
|
4614
4662
|
|
|
4615
|
-
Defined in: [lib/core.ts:
|
|
4663
|
+
Defined in: [lib/core.ts:849](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L849)
|
|
4616
4664
|
|
|
4617
4665
|
***
|
|
4618
4666
|
|
|
@@ -4620,7 +4668,7 @@ Defined in: [lib/core.ts:795](https://github.com/maiyunnet/kebab/blob/master/lib
|
|
|
4620
4668
|
|
|
4621
4669
|
> `optional` **headers?**: `IncomingHttpHeaders`
|
|
4622
4670
|
|
|
4623
|
-
Defined in: [lib/core.ts:
|
|
4671
|
+
Defined in: [lib/core.ts:852](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L852)
|
|
4624
4672
|
|
|
4625
4673
|
***
|
|
4626
4674
|
|
|
@@ -4628,7 +4676,7 @@ Defined in: [lib/core.ts:798](https://github.com/maiyunnet/kebab/blob/master/lib
|
|
|
4628
4676
|
|
|
4629
4677
|
> `optional` **hostname?**: `string`
|
|
4630
4678
|
|
|
4631
|
-
Defined in: [lib/core.ts:
|
|
4679
|
+
Defined in: [lib/core.ts:847](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L847)
|
|
4632
4680
|
|
|
4633
4681
|
***
|
|
4634
4682
|
|
|
@@ -4636,7 +4684,7 @@ Defined in: [lib/core.ts:793](https://github.com/maiyunnet/kebab/blob/master/lib
|
|
|
4636
4684
|
|
|
4637
4685
|
> `optional` **path?**: `string`
|
|
4638
4686
|
|
|
4639
|
-
Defined in: [lib/core.ts:
|
|
4687
|
+
Defined in: [lib/core.ts:845](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L845)
|
|
4640
4688
|
|
|
4641
4689
|
***
|
|
4642
4690
|
|
|
@@ -4644,7 +4692,7 @@ Defined in: [lib/core.ts:791](https://github.com/maiyunnet/kebab/blob/master/lib
|
|
|
4644
4692
|
|
|
4645
4693
|
> `optional` **req?**: `IncomingMessage` \| `Http2ServerRequest` \| `null`
|
|
4646
4694
|
|
|
4647
|
-
Defined in: [lib/core.ts:
|
|
4695
|
+
Defined in: [lib/core.ts:848](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L848)
|
|
4648
4696
|
|
|
4649
4697
|
***
|
|
4650
4698
|
|
|
@@ -4652,7 +4700,7 @@ Defined in: [lib/core.ts:794](https://github.com/maiyunnet/kebab/blob/master/lib
|
|
|
4652
4700
|
|
|
4653
4701
|
> `optional` **session?**: `Record`\<`string`, `any`\>
|
|
4654
4702
|
|
|
4655
|
-
Defined in: [lib/core.ts:
|
|
4703
|
+
Defined in: [lib/core.ts:851](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L851)
|
|
4656
4704
|
|
|
4657
4705
|
***
|
|
4658
4706
|
|
|
@@ -4660,7 +4708,7 @@ Defined in: [lib/core.ts:797](https://github.com/maiyunnet/kebab/blob/master/lib
|
|
|
4660
4708
|
|
|
4661
4709
|
> `optional` **urlFull?**: `string`
|
|
4662
4710
|
|
|
4663
|
-
Defined in: [lib/core.ts:
|
|
4711
|
+
Defined in: [lib/core.ts:846](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L846)
|
|
4664
4712
|
|
|
4665
4713
|
lib/core/type-aliases/TPm2Action.md
|
|
4666
4714
|
---
|
|
@@ -4749,7 +4797,7 @@ lib/core/variables/global.md
|
|
|
4749
4797
|
|
|
4750
4798
|
> `const` **global**: `Record`\<`string`, `any`\> = `{}`
|
|
4751
4799
|
|
|
4752
|
-
Defined in: [lib/core.ts:
|
|
4800
|
+
Defined in: [lib/core.ts:687](https://github.com/maiyunnet/kebab/blob/master/lib/core.ts#L687)
|
|
4753
4801
|
|
|
4754
4802
|
跨进程全局变量
|
|
4755
4803
|
|
|
@@ -15745,7 +15793,7 @@ lib/text/functions/getFileExt.md
|
|
|
15745
15793
|
|
|
15746
15794
|
> **getFileExt**(`path`): `string`
|
|
15747
15795
|
|
|
15748
|
-
Defined in: [lib/text.ts:
|
|
15796
|
+
Defined in: [lib/text.ts:533](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L533)
|
|
15749
15797
|
|
|
15750
15798
|
获取文件后缀
|
|
15751
15799
|
|
|
@@ -15774,7 +15822,7 @@ lib/text/functions/getFileNameExt.md
|
|
|
15774
15822
|
|
|
15775
15823
|
> **getFileNameExt**(`path`): `object`
|
|
15776
15824
|
|
|
15777
|
-
Defined in: [lib/text.ts:
|
|
15825
|
+
Defined in: [lib/text.ts:546](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L546)
|
|
15778
15826
|
|
|
15779
15827
|
获取文件名和后缀
|
|
15780
15828
|
|
|
@@ -15811,7 +15859,7 @@ lib/text/functions/getFilename.md
|
|
|
15811
15859
|
|
|
15812
15860
|
> **getFilename**(`path`, `ext?`): `string`
|
|
15813
15861
|
|
|
15814
|
-
Defined in: [lib/text.ts:
|
|
15862
|
+
Defined in: [lib/text.ts:513](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L513)
|
|
15815
15863
|
|
|
15816
15864
|
获取文件名
|
|
15817
15865
|
|
|
@@ -15846,7 +15894,7 @@ lib/text/functions/htmlescape.md
|
|
|
15846
15894
|
|
|
15847
15895
|
> **htmlescape**(`html`): `string`
|
|
15848
15896
|
|
|
15849
|
-
Defined in: [lib/text.ts:
|
|
15897
|
+
Defined in: [lib/text.ts:488](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L488)
|
|
15850
15898
|
|
|
15851
15899
|
HTML 特殊字符转换为实体字符
|
|
15852
15900
|
|
|
@@ -15875,7 +15923,7 @@ lib/text/functions/int2str.md
|
|
|
15875
15923
|
|
|
15876
15924
|
> **int2str**(`int`, `digits?`, `decimal?`): `string`
|
|
15877
15925
|
|
|
15878
|
-
Defined in: [lib/text.ts:
|
|
15926
|
+
Defined in: [lib/text.ts:746](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L746)
|
|
15879
15927
|
|
|
15880
15928
|
为解决精度问题,将整数转换为小数字符串
|
|
15881
15929
|
以下几个示例都是当 digits 为 3、decimal 为 2 时
|
|
@@ -16008,7 +16056,7 @@ lib/text/functions/isFalsy.md
|
|
|
16008
16056
|
|
|
16009
16057
|
> **isFalsy**(`val`): `val is TFalsy`
|
|
16010
16058
|
|
|
16011
|
-
Defined in: [lib/text.ts:
|
|
16059
|
+
Defined in: [lib/text.ts:697](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L697)
|
|
16012
16060
|
|
|
16013
16061
|
判断一个值是否是虚假的(为 null/undefined/空字符串/false/0)
|
|
16014
16062
|
|
|
@@ -16149,7 +16197,7 @@ lib/text/functions/isRealPath.md
|
|
|
16149
16197
|
|
|
16150
16198
|
> **isRealPath**(`path`): `boolean`
|
|
16151
16199
|
|
|
16152
|
-
Defined in: [lib/text.ts:
|
|
16200
|
+
Defined in: [lib/text.ts:500](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L500)
|
|
16153
16201
|
|
|
16154
16202
|
判断是否是绝对路径,是返回 true,相对路径返回 false
|
|
16155
16203
|
|
|
@@ -16178,7 +16226,7 @@ lib/text/functions/isTruthy.md
|
|
|
16178
16226
|
|
|
16179
16227
|
> **isTruthy**\<`T`\>(`val`): `val is Exclude<T, TFalsy>`
|
|
16180
16228
|
|
|
16181
|
-
Defined in: [lib/text.ts:
|
|
16229
|
+
Defined in: [lib/text.ts:705](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L705)
|
|
16182
16230
|
|
|
16183
16231
|
判断一个值是否是真实的(不为 null/undefined/空字符串/false/0)
|
|
16184
16232
|
|
|
@@ -16213,7 +16261,7 @@ lib/text/functions/logicalOr.md
|
|
|
16213
16261
|
|
|
16214
16262
|
> **logicalOr**\<`T`, `T2`\>(`v1`, `v2`): `T` *extends* [`TFalsy`](../type-aliases/TFalsy.md) ? `T2` : `T`
|
|
16215
16263
|
|
|
16216
|
-
Defined in: [lib/text.ts:
|
|
16264
|
+
Defined in: [lib/text.ts:714](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L714)
|
|
16217
16265
|
|
|
16218
16266
|
类似 || 运算符的效果
|
|
16219
16267
|
|
|
@@ -16398,7 +16446,7 @@ lib/text/functions/parseJson.md
|
|
|
16398
16446
|
|
|
16399
16447
|
> **parseJson**\<`T`\>(`str`): `false` \| `T`
|
|
16400
16448
|
|
|
16401
|
-
Defined in: [lib/text.ts:
|
|
16449
|
+
Defined in: [lib/text.ts:608](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L608)
|
|
16402
16450
|
|
|
16403
16451
|
将字符串解析为对象,返回 false 代表解析失败,支持 BigInt
|
|
16404
16452
|
|
|
@@ -16597,7 +16645,7 @@ lib/text/functions/str2int.md
|
|
|
16597
16645
|
|
|
16598
16646
|
> **str2int**(`str`, `digits?`): `number`
|
|
16599
16647
|
|
|
16600
|
-
Defined in: [lib/text.ts:
|
|
16648
|
+
Defined in: [lib/text.ts:728](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L728)
|
|
16601
16649
|
|
|
16602
16650
|
为解决精度问题,将字符串数字转换为整数显示
|
|
16603
16651
|
以下几个示例都是当 digits 为 2 时
|
|
@@ -16637,7 +16685,7 @@ lib/text/functions/stringifyBuffer.md
|
|
|
16637
16685
|
|
|
16638
16686
|
> **stringifyBuffer**(`buf`): `string`
|
|
16639
16687
|
|
|
16640
|
-
Defined in: [lib/text.ts:
|
|
16688
|
+
Defined in: [lib/text.ts:651](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L651)
|
|
16641
16689
|
|
|
16642
16690
|
输出文本格式的 buffer
|
|
16643
16691
|
|
|
@@ -16666,7 +16714,7 @@ lib/text/functions/stringifyJson.md
|
|
|
16666
16714
|
|
|
16667
16715
|
> **stringifyJson**(`obj`, `space?`): `string`
|
|
16668
16716
|
|
|
16669
|
-
Defined in: [lib/text.ts:
|
|
16717
|
+
Defined in: [lib/text.ts:638](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L638)
|
|
16670
16718
|
|
|
16671
16719
|
将对象转换为 json 字符串,返回 false 代表解析失败,支持 BigInt
|
|
16672
16720
|
|
|
@@ -16701,7 +16749,7 @@ lib/text/functions/stringifyResult.md
|
|
|
16701
16749
|
|
|
16702
16750
|
> **stringifyResult**(`rtn`): `string`
|
|
16703
16751
|
|
|
16704
|
-
Defined in: [lib/text.ts:
|
|
16752
|
+
Defined in: [lib/text.ts:568](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L568)
|
|
16705
16753
|
|
|
16706
16754
|
将普通的返回 JSON 对象序列化为字符串
|
|
16707
16755
|
|
|
@@ -16730,7 +16778,7 @@ lib/text/functions/trimJson.md
|
|
|
16730
16778
|
|
|
16731
16779
|
> **trimJson**(`json`): `any`
|
|
16732
16780
|
|
|
16733
|
-
Defined in: [lib/text.ts:
|
|
16781
|
+
Defined in: [lib/text.ts:659](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L659)
|
|
16734
16782
|
|
|
16735
16783
|
递归删除 json 中的字符串首尾空格,会返回一个新的对象
|
|
16736
16784
|
|
|
@@ -16930,7 +16978,7 @@ lib/text/type-aliases/TFalsy.md
|
|
|
16930
16978
|
|
|
16931
16979
|
> **TFalsy** = `false` \| `""` \| `0` \| `null` \| `undefined` \| *typeof* `NaN`
|
|
16932
16980
|
|
|
16933
|
-
Defined in: [lib/text.ts:
|
|
16981
|
+
Defined in: [lib/text.ts:691](https://github.com/maiyunnet/kebab/blob/master/lib/text.ts#L691)
|
|
16934
16982
|
|
|
16935
16983
|
虚假值类型
|
|
16936
16984
|
|
package/index.d.ts
CHANGED
package/index.js
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* --- 本文件用来定义每个目录实体地址的常量 ---
|
|
7
7
|
*/
|
|
8
8
|
/** --- 当前系统版本号 --- */
|
|
9
|
-
export const VER = '9.3.
|
|
9
|
+
export const VER = '9.3.6';
|
|
10
10
|
// --- 服务端用的路径 ---
|
|
11
11
|
const imu = decodeURIComponent(import.meta.url).replace('file://', '').replace(/^\/(\w:)/, '$1');
|
|
12
12
|
/** --- /xxx/xxx --- */
|
package/lib/core.d.ts
CHANGED
|
@@ -210,6 +210,14 @@ export declare function updateCode(sourcePath: string, path: string, hosts?: str
|
|
|
210
210
|
'result': boolean;
|
|
211
211
|
'return': string;
|
|
212
212
|
}>>;
|
|
213
|
+
/**
|
|
214
|
+
* --- 向本机或局域网 RPC 发送项目配置更新操作 ---
|
|
215
|
+
* @param path 项目路径,相对 Kebab 根
|
|
216
|
+
* @param key 要更新的键名(目前仅支持 staticVer)
|
|
217
|
+
* @param value 要更新的值
|
|
218
|
+
* @param hosts 局域网列表
|
|
219
|
+
*/
|
|
220
|
+
export declare function sendProject(path: string, key: string, value: string, hosts?: string[] | 'config'): Promise<string[]>;
|
|
213
221
|
/** --- log 设置的选项 --- */
|
|
214
222
|
export interface ILogOptions {
|
|
215
223
|
'path'?: string;
|
package/lib/core.js
CHANGED
|
@@ -532,7 +532,10 @@ export async function sendPm2(name, action = 'restart', hosts) {
|
|
|
532
532
|
if (hosts === 'config') {
|
|
533
533
|
hosts = globalConfig.hosts;
|
|
534
534
|
}
|
|
535
|
-
|
|
535
|
+
// --- 未传或 config 展开后为空数组,均回退到本机 ---
|
|
536
|
+
if (!hosts?.length) {
|
|
537
|
+
hosts = ['127.0.0.1'];
|
|
538
|
+
}
|
|
536
539
|
// --- 局域网模式 ---
|
|
537
540
|
const time = lTime.stamp();
|
|
538
541
|
/** --- 返回成功的 host --- */
|
|
@@ -569,7 +572,10 @@ export async function sendNpm(path, hosts) {
|
|
|
569
572
|
if (hosts === 'config') {
|
|
570
573
|
hosts = globalConfig.hosts;
|
|
571
574
|
}
|
|
572
|
-
|
|
575
|
+
// --- 未传或 config 展开后为空数组,均回退到本机 ---
|
|
576
|
+
if (!hosts?.length) {
|
|
577
|
+
hosts = ['127.0.0.1'];
|
|
578
|
+
}
|
|
573
579
|
// --- 局域网模式 ---
|
|
574
580
|
const time = lTime.stamp();
|
|
575
581
|
/** --- 返回成功的 host --- */
|
|
@@ -659,7 +665,10 @@ export async function updateCode(sourcePath, path, hosts, config = true, strict
|
|
|
659
665
|
if (hosts === 'config') {
|
|
660
666
|
hosts = globalConfig.hosts;
|
|
661
667
|
}
|
|
662
|
-
|
|
668
|
+
// --- 未传或 config 展开后为空数组,均回退到本机 ---
|
|
669
|
+
if (!hosts?.length) {
|
|
670
|
+
hosts = ['127.0.0.1'];
|
|
671
|
+
}
|
|
663
672
|
/** --- 返回成功的 host --- */
|
|
664
673
|
const rtn = {};
|
|
665
674
|
for (const host of hosts) {
|
|
@@ -692,6 +701,48 @@ export async function updateCode(sourcePath, path, hosts, config = true, strict
|
|
|
692
701
|
}
|
|
693
702
|
return rtn;
|
|
694
703
|
}
|
|
704
|
+
/**
|
|
705
|
+
* --- 向本机或局域网 RPC 发送项目配置更新操作 ---
|
|
706
|
+
* @param path 项目路径,相对 Kebab 根
|
|
707
|
+
* @param key 要更新的键名(目前仅支持 staticVer)
|
|
708
|
+
* @param value 要更新的值
|
|
709
|
+
* @param hosts 局域网列表
|
|
710
|
+
*/
|
|
711
|
+
export async function sendProject(path, key, value, hosts) {
|
|
712
|
+
if (hosts === 'config') {
|
|
713
|
+
hosts = globalConfig.hosts;
|
|
714
|
+
}
|
|
715
|
+
// --- 未传或 config 展开后为空数组,均回退到本机 ---
|
|
716
|
+
if (!hosts?.length) {
|
|
717
|
+
hosts = ['127.0.0.1'];
|
|
718
|
+
}
|
|
719
|
+
// --- 局域网模式 ---
|
|
720
|
+
const time = lTime.stamp();
|
|
721
|
+
/** --- 返回成功的 host --- */
|
|
722
|
+
const rtn = [];
|
|
723
|
+
for (const host of hosts) {
|
|
724
|
+
const res = await lUndici.get('http://' + host + ':' + globalConfig.rpcPort.toString() + '/' + lCrypto.aesEncrypt(lText.stringifyJson({
|
|
725
|
+
'action': 'project',
|
|
726
|
+
'time': time,
|
|
727
|
+
'path': path,
|
|
728
|
+
[key]: value
|
|
729
|
+
}), globalConfig.rpcSecret), {
|
|
730
|
+
'timeout': 2
|
|
731
|
+
});
|
|
732
|
+
const content = await res.getContent();
|
|
733
|
+
if (!content) {
|
|
734
|
+
continue;
|
|
735
|
+
}
|
|
736
|
+
const str = content.toString();
|
|
737
|
+
if (str === 'Done') {
|
|
738
|
+
rtn.push(host);
|
|
739
|
+
}
|
|
740
|
+
else {
|
|
741
|
+
debug('[CORE][sendProject] rpc server content error:', str);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
return rtn;
|
|
745
|
+
}
|
|
695
746
|
/**
|
|
696
747
|
* --- 写入文件日志 ---
|
|
697
748
|
* @param opt 选项
|
package/lib/text.js
CHANGED
|
@@ -393,7 +393,13 @@ export function queryParse(query) {
|
|
|
393
393
|
continue;
|
|
394
394
|
}
|
|
395
395
|
const pos = i.indexOf('=');
|
|
396
|
-
|
|
396
|
+
let key;
|
|
397
|
+
try {
|
|
398
|
+
key = decodeURIComponent(pos === -1 ? i : i.slice(0, pos));
|
|
399
|
+
}
|
|
400
|
+
catch {
|
|
401
|
+
key = pos === -1 ? i : i.slice(0, pos);
|
|
402
|
+
}
|
|
397
403
|
let value = '';
|
|
398
404
|
try {
|
|
399
405
|
value = pos === -1 ? '' : decodeURIComponent(i.slice(pos + 1));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@maiyunnet/kebab",
|
|
3
|
-
"version": "9.3.
|
|
3
|
+
"version": "9.3.6",
|
|
4
4
|
"description": "Simple, easy-to-use, and fully-featured Node.js framework that is ready-to-use out of the box.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"keywords": [
|
|
@@ -22,8 +22,8 @@
|
|
|
22
22
|
"#kebab/*": "./*"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@aws-sdk/client-s3": "^3.
|
|
26
|
-
"@aws-sdk/lib-storage": "^3.
|
|
25
|
+
"@aws-sdk/client-s3": "^3.1045.0",
|
|
26
|
+
"@aws-sdk/lib-storage": "^3.1045.0",
|
|
27
27
|
"@litert/http-client": "^1.1.2",
|
|
28
28
|
"@litert/mime": "^0.1.3",
|
|
29
29
|
"@litert/redis": "^3.2.1",
|
|
@@ -32,33 +32,33 @@
|
|
|
32
32
|
"@radix-ui/react-label": "^2.1.8",
|
|
33
33
|
"@radix-ui/react-slot": "^1.2.4",
|
|
34
34
|
"@radix-ui/react-switch": "^1.2.6",
|
|
35
|
-
"@tailwindcss/cli": "^4.
|
|
35
|
+
"@tailwindcss/cli": "^4.3.0",
|
|
36
36
|
"@types/ssh2": "^1.15.5",
|
|
37
|
-
"@zilliz/milvus2-sdk-node": "^
|
|
38
|
-
"ajv": "^8.
|
|
37
|
+
"@zilliz/milvus2-sdk-node": "^3.0.0",
|
|
38
|
+
"ajv": "^8.20.0",
|
|
39
39
|
"ajv-formats": "^3.0.1",
|
|
40
40
|
"class-variance-authority": "^0.7.1",
|
|
41
41
|
"clsx": "^2.1.1",
|
|
42
42
|
"ejs": "^5.0.2",
|
|
43
43
|
"esbuild": "^0.28.0",
|
|
44
44
|
"jszip": "^3.10.1",
|
|
45
|
-
"mysql2": "^3.22.
|
|
45
|
+
"mysql2": "^3.22.3",
|
|
46
46
|
"node-cron": "^4.2.1",
|
|
47
|
-
"openai": "^6.
|
|
47
|
+
"openai": "^6.37.0",
|
|
48
48
|
"pg": "^8.20.0",
|
|
49
|
-
"react": "^19.2.
|
|
50
|
-
"react-dom": "^19.2.
|
|
51
|
-
"react-router-dom": "^7.
|
|
49
|
+
"react": "^19.2.6",
|
|
50
|
+
"react-dom": "^19.2.6",
|
|
51
|
+
"react-router-dom": "^7.15.0",
|
|
52
52
|
"ssh2": "^1.17.0",
|
|
53
53
|
"svg-captcha": "^1.4.0",
|
|
54
54
|
"tailwind-merge": "^3.5.0",
|
|
55
|
-
"tencentcloud-sdk-nodejs": "^4.1.
|
|
56
|
-
"undici": "^8.
|
|
55
|
+
"tencentcloud-sdk-nodejs": "^4.1.227",
|
|
56
|
+
"undici": "^8.2.0"
|
|
57
57
|
},
|
|
58
58
|
"devDependencies": {
|
|
59
59
|
"@litert/eslint-plugin-rules": "^0.3.1",
|
|
60
60
|
"@types/ejs": "^3.1.5",
|
|
61
|
-
"@types/node": "^25.6.
|
|
61
|
+
"@types/node": "^25.6.2",
|
|
62
62
|
"@types/pg": "^8.20.0",
|
|
63
63
|
"@types/react": "^19.2.14",
|
|
64
64
|
"@types/react-dom": "^19.2.3",
|
package/sys/master.js
CHANGED
|
@@ -195,6 +195,63 @@ function createRpcListener() {
|
|
|
195
195
|
}
|
|
196
196
|
break;
|
|
197
197
|
}
|
|
198
|
+
case 'project': {
|
|
199
|
+
// --- 更新项目 kebab.json ---
|
|
200
|
+
if (!msg.path || typeof msg.path !== 'string') {
|
|
201
|
+
res.end('Invalid path');
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
// --- 参数校验前置,避免无效 IO ---
|
|
205
|
+
if (!msg.staticVer || typeof msg.staticVer !== 'string') {
|
|
206
|
+
res.end('Invalid staticVer');
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
209
|
+
let path = msg.path;
|
|
210
|
+
if (path.startsWith('/')) {
|
|
211
|
+
path = path.slice(1);
|
|
212
|
+
}
|
|
213
|
+
if (path.endsWith('/')) {
|
|
214
|
+
path = path.slice(0, -1);
|
|
215
|
+
}
|
|
216
|
+
// --- 拒绝路径穿越,防止跳出 ROOT_CWD ---
|
|
217
|
+
if (path.includes('..')) {
|
|
218
|
+
res.end('Invalid path');
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
/** --- 最终的项目根目录,以 / 结尾,但用户传入的无所谓 --- */
|
|
222
|
+
let to = kebab.ROOT_CWD + path;
|
|
223
|
+
if (!to.endsWith('/')) {
|
|
224
|
+
to += '/';
|
|
225
|
+
}
|
|
226
|
+
if (!await lFs.isDir(to)) {
|
|
227
|
+
res.end('Path not found: ' + to);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const projectFile = to + 'kebab.json';
|
|
231
|
+
if (!await lFs.isFile(projectFile)) {
|
|
232
|
+
res.end('kebab.json not found in project path');
|
|
233
|
+
return;
|
|
234
|
+
}
|
|
235
|
+
const projectContent = await lFs.getContent(projectFile, 'utf8');
|
|
236
|
+
if (!projectContent) {
|
|
237
|
+
res.end('Failed to read kebab.json');
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
const projectJson = lText.parseJson(projectContent);
|
|
241
|
+
if (!projectJson) {
|
|
242
|
+
res.end('Invalid kebab.json');
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
// --- 只允许更新 set.staticVer 字段 ---
|
|
246
|
+
projectJson.set ??= {};
|
|
247
|
+
projectJson.set.staticVer = msg.staticVer;
|
|
248
|
+
const wrtn = await lFs.putContent(projectFile, lText.stringifyJson(projectJson, 4));
|
|
249
|
+
if (!wrtn) {
|
|
250
|
+
res.end('Failed to write kebab.json');
|
|
251
|
+
return;
|
|
252
|
+
}
|
|
253
|
+
break;
|
|
254
|
+
}
|
|
198
255
|
case 'code': {
|
|
199
256
|
// --- 更新 code 代码包 ---
|
|
200
257
|
const rtn = await sRoute.getFormData(req);
|
|
@@ -221,9 +278,12 @@ function createRpcListener() {
|
|
|
221
278
|
to += '/';
|
|
222
279
|
}
|
|
223
280
|
if (!await lFs.isDir(to)) {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
281
|
+
if (rtn.post['strict'] === '1') {
|
|
282
|
+
res.end('Path not found: ' + to);
|
|
283
|
+
await sRoute.unlinkUploadFiles(rtn.files);
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
await lFs.mkdir(to);
|
|
227
287
|
}
|
|
228
288
|
const buf = await lFs.getContent(file.path);
|
|
229
289
|
if (!buf) {
|
|
@@ -300,20 +360,23 @@ function createRpcListener() {
|
|
|
300
360
|
// --- 规则 2:kebab 子项目目录中,仅允许部署 ctr/data/stc/view/lib 子文件夹内的内容 ---
|
|
301
361
|
// --- 快速跳过:zip 中没有 kebab.json 时整个规则无需执行 ---
|
|
302
362
|
if (kebabProjectDirs.size > 0) {
|
|
303
|
-
// ---
|
|
304
|
-
|
|
305
|
-
|
|
363
|
+
// --- 找最浅(最外层)匹配的 kebab 项目目录 ---
|
|
364
|
+
// --- 以最浅匹配为准,确保根层 kebab 规则优先于嵌套项目 ---
|
|
365
|
+
// --- 例如 backup/ 自身也有 kebab.json,longestMatch 会选 backup/,使其根文件通过 ---
|
|
366
|
+
// --- 改用 shortestMatch 则选根 "",backup 的第一段不在白名单中,正确排除 ---
|
|
367
|
+
/** --- 当前文件所属的最浅 kebab 子项目目录;无匹配则为 null --- */
|
|
368
|
+
let shortestMatch = null;
|
|
306
369
|
for (const kdir of kebabProjectDirs) {
|
|
307
|
-
/** --- 当前 kdir 是否比已有的
|
|
308
|
-
const
|
|
309
|
-
if (pat.startsWith(kdir) &&
|
|
310
|
-
|
|
370
|
+
/** --- 当前 kdir 是否比已有的 shortestMatch 更浅(路径更短)--- */
|
|
371
|
+
const isShallower = shortestMatch === null || kdir.length < shortestMatch.length;
|
|
372
|
+
if (pat.startsWith(kdir) && isShallower) {
|
|
373
|
+
shortestMatch = kdir;
|
|
311
374
|
}
|
|
312
375
|
}
|
|
313
|
-
if (
|
|
376
|
+
if (shortestMatch !== null) {
|
|
314
377
|
// --- 取相对于 kebab 项目目录的路径,检查第一级子目录 ---
|
|
315
|
-
/** --- 相对路径,例如若 pat 为 "www/pika/ctr/" 且
|
|
316
|
-
const relPath = pat.slice(
|
|
378
|
+
/** --- 相对路径,例如若 pat 为 "www/pika/ctr/" 且 shortestMatch 为 "www/pika/",则 relPath 为 "ctr/" --- */
|
|
379
|
+
const relPath = pat.slice(shortestMatch.length);
|
|
317
380
|
if (relPath) {
|
|
318
381
|
/** --- 路径的第一级子目录名,例如 "ctr" 或 "data",用于判断是否在允许列表中 --- */
|
|
319
382
|
const firstSeg = relPath.split('/')[0];
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
* 如需打包为 .bundle.js,执行:node ./source/main build
|
|
20
20
|
*
|
|
21
21
|
* 【Tailwind CSS 构建】
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* 需提前执行 node ./source/main build -d source/www/example/stc 生成 CSS 产物。
|
|
23
|
+
* 框架通过 _staticPath 和 _staticVer 自动拼接带版本号 URL;
|
|
24
|
+
* import map、props JSON、水合脚本均由框架自动注入 HTML,组件无需手动处理。
|
|
25
25
|
*/
|
|
26
26
|
interface IUser {
|
|
27
27
|
'id': string;
|
|
@@ -42,17 +42,11 @@ interface IProps {
|
|
|
42
42
|
'_staticVer': string;
|
|
43
43
|
/** --- 框架注入:BrowserRouter 的 basename,如 /test/react-router-page --- */
|
|
44
44
|
'_routerBase'?: string;
|
|
45
|
-
/** --- 框架注入:import map JSON 字符串 --- */
|
|
46
|
-
'_importMapJson'?: string;
|
|
47
|
-
/** --- 框架注入:水合脚本 --- */
|
|
48
|
-
'_hydrateScript'?: string;
|
|
49
|
-
/** --- 框架注入:fullProps 序列化 JSON --- */
|
|
50
|
-
'_propsJson'?: string;
|
|
51
45
|
}
|
|
52
46
|
/**
|
|
53
47
|
* --- Kebab React BrowserRouter 全页面演示 ---
|
|
54
48
|
* 框架负责用 StaticRouter(服务端)/ BrowserRouter(客户端)包裹本组件,
|
|
55
49
|
* 组件内部只需使用 Routes/Route/Link 等,无需自行包裹 Router。
|
|
56
50
|
*/
|
|
57
|
-
export default function ReactRouterPage({ title, serverTime, node, users, user, _urlBase, _urlStc, _staticVer,
|
|
51
|
+
export default function ReactRouterPage({ title, serverTime, node, users, user, _urlBase, _urlStc, _staticVer, }: IProps): import("react/jsx-runtime").JSX.Element;
|
|
58
52
|
export {};
|
|
@@ -20,9 +20,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
20
20
|
* 如需打包为 .bundle.js,执行:node ./source/main build
|
|
21
21
|
*
|
|
22
22
|
* 【Tailwind CSS 构建】
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
23
|
+
* 需提前执行 node ./source/main build -d source/www/example/stc 生成 CSS 产物。
|
|
24
|
+
* 框架通过 _staticPath 和 _staticVer 自动拼接带版本号 URL;
|
|
25
|
+
* import map、props JSON、水合脚本均由框架自动注入 HTML,组件无需手动处理。
|
|
26
26
|
*/
|
|
27
27
|
import { useState, useEffect } from 'react';
|
|
28
28
|
import { Routes, Route, Link, NavLink, useParams, useNavigate, useLocation, Outlet } from 'react-router-dom';
|
|
@@ -135,8 +135,6 @@ function PageNotFound() {
|
|
|
135
135
|
* 框架负责用 StaticRouter(服务端)/ BrowserRouter(客户端)包裹本组件,
|
|
136
136
|
* 组件内部只需使用 Routes/Route/Link 等,无需自行包裹 Router。
|
|
137
137
|
*/
|
|
138
|
-
export default function ReactRouterPage({ title, serverTime, node, users, user, _urlBase, _urlStc, _staticVer,
|
|
139
|
-
return (_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx("meta", { charSet: "UTF-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), _jsx("title", { suppressHydrationWarning: true, children: title }),
|
|
140
|
-
? _jsx("script", { src: "https://cdn.tailwindcss.com" })
|
|
141
|
-
: _jsx("link", { rel: "stylesheet", href: `${_urlStc}view/react-router-page.css?v=${_staticVer}` }), _importMapJson && (_jsx("script", { type: "importmap", dangerouslySetInnerHTML: { '__html': _importMapJson } }))] }), _jsxs("body", { className: "bg-slate-50 min-h-screen", children: [_jsxs("div", { className: "max-w-2xl mx-auto px-4 py-10 space-y-6", children: [_jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold text-slate-900", children: "Kebab React Router" }), _jsxs("p", { className: "text-slate-500 mt-1 text-sm", children: [_jsx("code", { className: "bg-slate-100 px-1.5 py-0.5 rounded font-mono text-xs", children: "router: 'browser'" }), "\u00A0mode \u2014 URL synced with routes"] })] }), _jsx("a", { href: `${_urlBase}`, className: "text-xs text-slate-400 hover:text-slate-600 transition-colors mt-1", children: "Back to Index" })] }), _jsx("div", { className: "bg-white rounded-xl shadow-sm border border-slate-200 px-4 py-3", children: _jsx(NavBar, {}) }), _jsx("div", { className: "bg-white rounded-xl shadow-sm border border-slate-200 p-6", children: _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(PageHome, { serverTime: serverTime, node: node }) }), _jsx(Route, { path: "/about", element: _jsx(PageAbout, {}) }), _jsx(Route, { path: "/user", element: _jsx(PageUsers, { users: users, urlBase: _urlBase }) }), _jsx(Route, { path: "/user/:id", element: _jsx(PageUserDetail, { user: user, urlBase: _urlBase }), children: _jsx(Route, { path: "profile", element: _jsx(PageUserProfile, {}) }) }), _jsx(Route, { path: "*", element: _jsx(PageNotFound, {}) })] }) }), _jsxs(Card, { className: "text-xs text-slate-500 space-y-1.5", children: [_jsx("p", { className: "font-semibold text-slate-700 text-sm", children: "How It Works" }), _jsxs("p", { children: ["\u2022 Server: framework wraps with ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "StaticRouter" }), " to SSR the matching route"] }), _jsxs("p", { children: ["\u2022 Client: hydration script wraps with ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "BrowserRouter" }), " for URL-synced navigation"] }), _jsxs("p", { children: ["\u2022 Data: one backend method (", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "_getRouteData" }), ") serves both SSR props and SPA API"] }), _jsxs("p", { children: ["\u2022 Deep links like ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "/test/react-router-page/user/42" }), " work out of the box"] })] })] }), _propsJson && (_jsx("script", { id: "__kebab_props__", type: "application/json", suppressHydrationWarning: true, dangerouslySetInnerHTML: { '__html': _propsJson } })), _hydrateScript && (_jsx("script", { type: "module", suppressHydrationWarning: true, dangerouslySetInnerHTML: { '__html': _hydrateScript } }))] })] }));
|
|
138
|
+
export default function ReactRouterPage({ title, serverTime, node, users, user, _urlBase, _urlStc, _staticVer, }) {
|
|
139
|
+
return (_jsxs("html", { lang: "en", children: [_jsxs("head", { children: [_jsx("meta", { charSet: "UTF-8" }), _jsx("meta", { name: "viewport", content: "width=device-width, initial-scale=1" }), _jsx("title", { suppressHydrationWarning: true, children: title }), _jsx("link", { rel: "stylesheet", href: `${_urlStc}view/react-router-page.css?v=${_staticVer}` })] }), _jsx("body", { className: "bg-slate-50 min-h-screen", children: _jsxs("div", { className: "max-w-2xl mx-auto px-4 py-10 space-y-6", children: [_jsxs("div", { className: "flex items-start justify-between", children: [_jsxs("div", { children: [_jsx("h1", { className: "text-2xl font-bold text-slate-900", children: "Kebab React Router" }), _jsxs("p", { className: "text-slate-500 mt-1 text-sm", children: [_jsx("code", { className: "bg-slate-100 px-1.5 py-0.5 rounded font-mono text-xs", children: "router: 'browser'" }), "\u00A0mode \u2014 URL synced with routes"] })] }), _jsx("a", { href: `${_urlBase}`, className: "text-xs text-slate-400 hover:text-slate-600 transition-colors mt-1", children: "Back to Index" })] }), _jsx("div", { className: "bg-white rounded-xl shadow-sm border border-slate-200 px-4 py-3", children: _jsx(NavBar, {}) }), _jsx("div", { className: "bg-white rounded-xl shadow-sm border border-slate-200 p-6", children: _jsxs(Routes, { children: [_jsx(Route, { path: "/", element: _jsx(PageHome, { serverTime: serverTime, node: node }) }), _jsx(Route, { path: "/about", element: _jsx(PageAbout, {}) }), _jsx(Route, { path: "/user", element: _jsx(PageUsers, { users: users, urlBase: _urlBase }) }), _jsx(Route, { path: "/user/:id", element: _jsx(PageUserDetail, { user: user, urlBase: _urlBase }), children: _jsx(Route, { path: "profile", element: _jsx(PageUserProfile, {}) }) }), _jsx(Route, { path: "*", element: _jsx(PageNotFound, {}) })] }) }), _jsxs(Card, { className: "text-xs text-slate-500 space-y-1.5", children: [_jsx("p", { className: "font-semibold text-slate-700 text-sm", children: "How It Works" }), _jsxs("p", { children: ["\u2022 Server: framework wraps with ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "StaticRouter" }), " to SSR the matching route"] }), _jsxs("p", { children: ["\u2022 Client: hydration script wraps with ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "BrowserRouter" }), " for URL-synced navigation"] }), _jsxs("p", { children: ["\u2022 Data: one backend method (", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "_getRouteData" }), ") serves both SSR props and SPA API"] }), _jsxs("p", { children: ["\u2022 Deep links like ", _jsx("code", { className: "bg-slate-100 px-1 rounded", children: "/test/react-router-page/user/42" }), " work out of the box"] })] })] }) })] }));
|
|
142
140
|
}
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
* 如需打包为 .bundle.js,执行:node ./source/main build
|
|
20
20
|
*
|
|
21
21
|
* 【Tailwind CSS 构建】
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
22
|
+
* 需提前执行 node ./source/main build -d source/www/example/stc 生成 CSS 产物。
|
|
23
|
+
* 框架通过 _staticPath 和 _staticVer 自动拼接带版本号 URL;
|
|
24
|
+
* import map、props JSON、水合脚本均由框架自动注入 HTML,组件无需手动处理。
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
import { useState, useEffect } from 'react';
|
|
@@ -49,12 +49,6 @@ interface IProps {
|
|
|
49
49
|
'_staticVer': string;
|
|
50
50
|
/** --- 框架注入:BrowserRouter 的 basename,如 /test/react-router-page --- */
|
|
51
51
|
'_routerBase'?: string;
|
|
52
|
-
/** --- 框架注入:import map JSON 字符串 --- */
|
|
53
|
-
'_importMapJson'?: string;
|
|
54
|
-
/** --- 框架注入:水合脚本 --- */
|
|
55
|
-
'_hydrateScript'?: string;
|
|
56
|
-
/** --- 框架注入:fullProps 序列化 JSON --- */
|
|
57
|
-
'_propsJson'?: string;
|
|
58
52
|
}
|
|
59
53
|
|
|
60
54
|
// --- 基础控件 ---
|
|
@@ -334,7 +328,7 @@ function PageNotFound() {
|
|
|
334
328
|
* 组件内部只需使用 Routes/Route/Link 等,无需自行包裹 Router。
|
|
335
329
|
*/
|
|
336
330
|
export default function ReactRouterPage({
|
|
337
|
-
title, serverTime, node, users, user, _urlBase, _urlStc, _staticVer,
|
|
331
|
+
title, serverTime, node, users, user, _urlBase, _urlStc, _staticVer,
|
|
338
332
|
}: IProps) {
|
|
339
333
|
return (
|
|
340
334
|
<html lang="en">
|
|
@@ -343,14 +337,9 @@ export default function ReactRouterPage({
|
|
|
343
337
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
344
338
|
{/* eslint-disable-next-line @typescript-eslint/naming-convention */}
|
|
345
339
|
<title suppressHydrationWarning>{title}</title>
|
|
346
|
-
{/* ---
|
|
347
|
-
{
|
|
348
|
-
|
|
349
|
-
: <link rel="stylesheet" href={`${_urlStc}view/react-router-page.css?v=${_staticVer}`} />}
|
|
350
|
-
{/* --- import map:让浏览器识别 bare import,esm.sh 自动解析依赖 --- */}
|
|
351
|
-
{_importMapJson && (
|
|
352
|
-
<script type="importmap" dangerouslySetInnerHTML={{ '__html': _importMapJson }} />
|
|
353
|
-
)}
|
|
340
|
+
{/* --- import map 由框架自动注入在此标签前,无需手动添加 --- */}
|
|
341
|
+
{/* --- dev: 需先执行 node ./source/main build -d source/www/example/stc 生成 CSS --- */}
|
|
342
|
+
<link rel="stylesheet" href={`${_urlStc}view/react-router-page.css?v=${_staticVer}`} />
|
|
354
343
|
</head>
|
|
355
344
|
<body className="bg-slate-50 min-h-screen">
|
|
356
345
|
<div className="max-w-2xl mx-auto px-4 py-10 space-y-6">
|
|
@@ -403,23 +392,7 @@ export default function ReactRouterPage({
|
|
|
403
392
|
</Card>
|
|
404
393
|
</div>
|
|
405
394
|
|
|
406
|
-
{/* ---
|
|
407
|
-
{_propsJson && (
|
|
408
|
-
<script
|
|
409
|
-
id="__kebab_props__"
|
|
410
|
-
type="application/json"
|
|
411
|
-
suppressHydrationWarning
|
|
412
|
-
dangerouslySetInnerHTML={{ '__html': _propsJson }}
|
|
413
|
-
/>
|
|
414
|
-
)}
|
|
415
|
-
{/* --- 框架注入:水合脚本 --- */}
|
|
416
|
-
{_hydrateScript && (
|
|
417
|
-
<script
|
|
418
|
-
type="module"
|
|
419
|
-
suppressHydrationWarning
|
|
420
|
-
dangerouslySetInnerHTML={{ '__html': _hydrateScript }}
|
|
421
|
-
/>
|
|
422
|
-
)}
|
|
395
|
+
{/* --- props JSON + 水合脚本由框架自动注入在此标签前,无需手动添加 --- */}
|
|
423
396
|
</body>
|
|
424
397
|
</html>
|
|
425
398
|
);
|