fluxion-ts 0.0.4
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/.oxlintrc.json +64 -0
- package/.prettierrc +6 -0
- package/AGENTS.md +3 -0
- package/Dockerfile +13 -0
- package/LICENSE +21 -0
- package/README.md +11 -0
- package/document/index.html +16 -0
- package/document/src/main.tsx +8 -0
- package/document/src/styles.css +321 -0
- package/document/src/view/App.tsx +304 -0
- package/document/src/view/CodeBlock.tsx +11 -0
- package/document/src/view/Section.tsx +18 -0
- package/document/vite.config.ts +23 -0
- package/draft/vibe.md +50 -0
- package/package.json +66 -0
- package/rollup.config.mjs +102 -0
- package/scripts/build-image.ts +13 -0
- package/scripts/bump-version.ts +12 -0
- package/scripts/configs.ts +79 -0
- package/scripts/lines.ts +54 -0
- package/scripts/publish.ts +6 -0
- package/src/common/consts.ts +30 -0
- package/src/common/dtm.ts +10 -0
- package/src/common/logger.ts +145 -0
- package/src/core/meta-api.ts +48 -0
- package/src/core/server.ts +447 -0
- package/src/core/types.d.ts +6 -0
- package/src/core/utils/headers.ts +34 -0
- package/src/core/utils/request.ts +145 -0
- package/src/core/utils/send-json.ts +21 -0
- package/src/index.ts +11 -0
- package/src/workers/file-runtime.ts +1071 -0
- package/src/workers/handler-worker-pool.ts +754 -0
- package/src/workers/handler-worker.ts +1029 -0
- package/src/workers/options.ts +77 -0
- package/src/workers/protocol.d.ts +186 -0
- package/tests/core/dynamic-directory.test.ts +48 -0
- package/tests/core/file-runtime.test.ts +347 -0
- package/tests/core/server-options.test.ts +204 -0
- package/tests/e2e/fluxion-server.e2e-spec.ts +225 -0
- package/tests/helpers/test-utils.ts +81 -0
- package/tsconfig.json +22 -0
- package/vitest.config.ts +24 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
import { CodeBlock } from './CodeBlock.js';
|
|
2
|
+
import { Section } from './Section.js';
|
|
3
|
+
|
|
4
|
+
const startCode = `# 1) 安装依赖
|
|
5
|
+
pnpm install
|
|
6
|
+
|
|
7
|
+
# 2) 启动 fluxion(默认读取 ./dynamicDirectory)
|
|
8
|
+
pnpm dev
|
|
9
|
+
|
|
10
|
+
# 3) 启动文档站点(当前页面)
|
|
11
|
+
pnpm doc:dev`;
|
|
12
|
+
|
|
13
|
+
const configCode = `{
|
|
14
|
+
"dynamicDirectory": "./dynamicDirectory",
|
|
15
|
+
"host": "127.0.0.1",
|
|
16
|
+
"port": 3000
|
|
17
|
+
}`;
|
|
18
|
+
|
|
19
|
+
const treeCode = `dynamicDirectory/
|
|
20
|
+
├── aaa/
|
|
21
|
+
│ ├── bb/
|
|
22
|
+
│ │ ├── cc/index.mjs # 动态路由 /aaa/bb/cc(优先)
|
|
23
|
+
│ │ └── cc.mjs # 动态路由 /aaa/bb/cc(次优先)
|
|
24
|
+
│ ├── public/app.js # 静态资源 /aaa/public/app.js
|
|
25
|
+
│ └── page.html # 静态资源 /aaa/page.html
|
|
26
|
+
├── index.mjs # 动态路由 /
|
|
27
|
+
└── _lib/
|
|
28
|
+
├── tool.mjs # 不可路由(_ 前缀目录)
|
|
29
|
+
└── helper.js # 不可路由(_ 前缀目录)`;
|
|
30
|
+
|
|
31
|
+
const handlerCode = `// dynamicDirectory/aaa/bb/cc/index.mjs
|
|
32
|
+
export default function handler(req, res) {
|
|
33
|
+
res.statusCode = 200;
|
|
34
|
+
res.setHeader('content-type', 'application/json; charset=utf-8');
|
|
35
|
+
res.end(JSON.stringify({
|
|
36
|
+
ok: true,
|
|
37
|
+
method: req.method,
|
|
38
|
+
url: req.url,
|
|
39
|
+
}));
|
|
40
|
+
}`;
|
|
41
|
+
|
|
42
|
+
const routeDecisionCode = `请求进入后,按以下顺序判定:
|
|
43
|
+
|
|
44
|
+
1. 先匹配元接口 /_fluxion/*
|
|
45
|
+
2. URL 解析与安全校验:
|
|
46
|
+
- 段不能为空、不能是 . 或 ..
|
|
47
|
+
- 段不能包含 / 或 \\
|
|
48
|
+
- 任意段以 _ 开头 => 直接 404
|
|
49
|
+
3. 动态路由判定(仅 .mjs 作为 handler):
|
|
50
|
+
- 先试 <path>/index.mjs
|
|
51
|
+
- 再试 <path>.mjs
|
|
52
|
+
- 命中后加载 default 导出并执行
|
|
53
|
+
4. 若动态未命中,再判定静态文件:
|
|
54
|
+
- 仅 GET/HEAD
|
|
55
|
+
- .mjs 永不当静态文件返回
|
|
56
|
+
- 其他文件存在则直接返回
|
|
57
|
+
5. 仍未命中 => 404`;
|
|
58
|
+
|
|
59
|
+
const cacheCode = `handler 缓存键 = "mtimeMs:size"
|
|
60
|
+
|
|
61
|
+
- 首次访问:import(file://...?.v=mtime:size)
|
|
62
|
+
- 后续访问:
|
|
63
|
+
- mtime/size 未变化 -> 复用缓存函数
|
|
64
|
+
- mtime 或 size 变化 -> 重新 import 新版本
|
|
65
|
+
|
|
66
|
+
这意味着:只要文件内容导致 mtime 或 size 变化,下一次请求就会热更新。`;
|
|
67
|
+
|
|
68
|
+
const metaRoutesCode = `GET /_fluxion/routes
|
|
69
|
+
|
|
70
|
+
返回示例:
|
|
71
|
+
{
|
|
72
|
+
"routes": {
|
|
73
|
+
"handlers": [
|
|
74
|
+
{
|
|
75
|
+
"route": "/aaa/bb/cc",
|
|
76
|
+
"file": "aaa/bb/cc/index.mjs",
|
|
77
|
+
"version": "1740751930123.123:289"
|
|
78
|
+
}
|
|
79
|
+
],
|
|
80
|
+
"staticFiles": [
|
|
81
|
+
{
|
|
82
|
+
"route": "/aaa/public/app.js",
|
|
83
|
+
"file": "aaa/public/app.js",
|
|
84
|
+
"version": "1740751930456.456:31"
|
|
85
|
+
}
|
|
86
|
+
]
|
|
87
|
+
}
|
|
88
|
+
}`;
|
|
89
|
+
|
|
90
|
+
const healthzCode = `GET /_fluxion/healthz
|
|
91
|
+
|
|
92
|
+
返回示例:
|
|
93
|
+
{
|
|
94
|
+
"ok": true,
|
|
95
|
+
"now": 1740751930999
|
|
96
|
+
}`;
|
|
97
|
+
|
|
98
|
+
const uploadCode = `curl -X POST \
|
|
99
|
+
'http://127.0.0.1:3000/_fluxion/upload?filename=my-module.tar.gz' \
|
|
100
|
+
-H 'content-type: application/octet-stream' \
|
|
101
|
+
--data-binary @./my-module.tar.gz`;
|
|
102
|
+
|
|
103
|
+
const uploadRuleCode = `上传仅支持:.tar / .tar.gz / .tgz
|
|
104
|
+
|
|
105
|
+
解压后布局判定:
|
|
106
|
+
|
|
107
|
+
A) 仅一个顶层目录
|
|
108
|
+
-> moduleName = 顶层目录名
|
|
109
|
+
-> 安装为 dynamicDirectory/<moduleName>
|
|
110
|
+
|
|
111
|
+
B) 多个顶层项(文件或目录)
|
|
112
|
+
-> moduleName = 压缩包文件名(去扩展名)
|
|
113
|
+
-> 所有顶层项复制到 dynamicDirectory/<moduleName>
|
|
114
|
+
|
|
115
|
+
C) 解压后没有可用内容
|
|
116
|
+
-> 400(Invalid archive structure)`;
|
|
117
|
+
|
|
118
|
+
const requestMapCode = `访问路径 -> 结果
|
|
119
|
+
|
|
120
|
+
/aaa/bb/cc -> 查找 aaa/bb/cc/index.mjs,再查 aaa/bb/cc.mjs
|
|
121
|
+
/aaa/public/app.js -> 若文件存在,作为静态文件返回
|
|
122
|
+
/aaa/bb/cc.mjs -> 不直接暴露源码,返回 404
|
|
123
|
+
/_lib/x -> _ 前缀目录,不路由,返回 404
|
|
124
|
+
/_fluxion/routes -> 元接口,返回当前路由快照`;
|
|
125
|
+
|
|
126
|
+
export function App() {
|
|
127
|
+
return (
|
|
128
|
+
<div class="doc-page">
|
|
129
|
+
<div class="bg-glow bg-glow-left" />
|
|
130
|
+
<div class="bg-glow bg-glow-right" />
|
|
131
|
+
|
|
132
|
+
<header class="hero">
|
|
133
|
+
<p class="eyebrow">Fluxion 使用说明(中文版)</p>
|
|
134
|
+
<h1 class="hero-title">文件即路由:.mjs 动态处理,.js 静态返回</h1>
|
|
135
|
+
<p class="hero-copy">
|
|
136
|
+
Fluxion 是一个基于 Node.js HTTP 的元服务器。它不要求固定的 server/web 目录,直接以
|
|
137
|
+
<code class="inline-code">dynamicDirectory</code>
|
|
138
|
+
中的文件结构来决定路由行为。
|
|
139
|
+
</p>
|
|
140
|
+
<div class="hero-actions">
|
|
141
|
+
<a href="#quick-start" class="button button-primary">
|
|
142
|
+
快速开始
|
|
143
|
+
</a>
|
|
144
|
+
<a href="#decision" class="button button-ghost">
|
|
145
|
+
判定规则
|
|
146
|
+
</a>
|
|
147
|
+
</div>
|
|
148
|
+
</header>
|
|
149
|
+
|
|
150
|
+
<nav class="toc">
|
|
151
|
+
<a href="#quick-start">快速开始</a>
|
|
152
|
+
<a href="#layout">目录约定</a>
|
|
153
|
+
<a href="#decision">判定顺序</a>
|
|
154
|
+
<a href="#handler">动态加载</a>
|
|
155
|
+
<a href="#meta-api">元接口</a>
|
|
156
|
+
<a href="#upload">上传规则</a>
|
|
157
|
+
<a href="#examples">请求示例</a>
|
|
158
|
+
</nav>
|
|
159
|
+
|
|
160
|
+
<main class="content">
|
|
161
|
+
<Section id="quick-start" title="快速开始" lead="先跑起来,再按规则组织文件。">
|
|
162
|
+
<div class="grid-two">
|
|
163
|
+
<article class="panel">
|
|
164
|
+
<h3 class="panel-title">启动命令</h3>
|
|
165
|
+
<CodeBlock code={startCode} />
|
|
166
|
+
</article>
|
|
167
|
+
<article class="panel">
|
|
168
|
+
<h3 class="panel-title">核心配置</h3>
|
|
169
|
+
<p class="panel-note">
|
|
170
|
+
运行时配置等价于下面 JSON。默认值来自环境变量:
|
|
171
|
+
<code class="inline-code">DYNAMIC_DIRECTORY</code>、
|
|
172
|
+
<code class="inline-code">HOST</code>、
|
|
173
|
+
<code class="inline-code">PORT</code>。
|
|
174
|
+
</p>
|
|
175
|
+
<CodeBlock code={configCode} />
|
|
176
|
+
</article>
|
|
177
|
+
</div>
|
|
178
|
+
</Section>
|
|
179
|
+
|
|
180
|
+
<Section
|
|
181
|
+
id="layout"
|
|
182
|
+
title="目录约定"
|
|
183
|
+
lead="不再强制 server/web。所有内容都直接放在 dynamicDirectory 下。"
|
|
184
|
+
>
|
|
185
|
+
<div class="panel">
|
|
186
|
+
<CodeBlock code={treeCode} />
|
|
187
|
+
<ul class="check-list panel-note-list">
|
|
188
|
+
<li>
|
|
189
|
+
<code class="inline-code">.mjs</code>:作为动态 handler,必须
|
|
190
|
+
<code class="inline-code">export default (req, res) => {}</code>。
|
|
191
|
+
</li>
|
|
192
|
+
<li>
|
|
193
|
+
<code class="inline-code">.js</code>:作为静态资源返回(也是推荐的前端脚本后缀)。
|
|
194
|
+
</li>
|
|
195
|
+
<li>其他非 .mjs 文件(如 .html/.css/.json)也会按静态文件处理。</li>
|
|
196
|
+
<li>
|
|
197
|
+
目录名以 <code class="inline-code">_</code> 开头(如 <code class="inline-code">_lib/</code>)永不路由。
|
|
198
|
+
</li>
|
|
199
|
+
</ul>
|
|
200
|
+
</div>
|
|
201
|
+
</Section>
|
|
202
|
+
|
|
203
|
+
<Section
|
|
204
|
+
id="decision"
|
|
205
|
+
title="请求判定顺序(最重要)"
|
|
206
|
+
lead="同一个请求会严格按固定顺序处理,这决定了最终命中哪个文件。"
|
|
207
|
+
>
|
|
208
|
+
<div class="grid-two">
|
|
209
|
+
<article class="panel">
|
|
210
|
+
<h3 class="panel-title">判定流程</h3>
|
|
211
|
+
<CodeBlock code={routeDecisionCode} />
|
|
212
|
+
</article>
|
|
213
|
+
<article class="panel panel-warning">
|
|
214
|
+
<h3 class="panel-title">安全与保留规则</h3>
|
|
215
|
+
<ul class="warning-list">
|
|
216
|
+
<li>
|
|
217
|
+
<code class="inline-code">/_fluxion/*</code> 是系统保留前缀,优先级最高。
|
|
218
|
+
</li>
|
|
219
|
+
<li>路径包含非法段或解码失败时,会直接返回 404。</li>
|
|
220
|
+
<li>
|
|
221
|
+
<code class="inline-code">.mjs</code> 文件不会被当静态资源直接下载。
|
|
222
|
+
</li>
|
|
223
|
+
<li>
|
|
224
|
+
<code class="inline-code">_</code> 前缀目录即使存在文件,也不会暴露路由。
|
|
225
|
+
</li>
|
|
226
|
+
</ul>
|
|
227
|
+
</article>
|
|
228
|
+
</div>
|
|
229
|
+
</Section>
|
|
230
|
+
|
|
231
|
+
<Section
|
|
232
|
+
id="handler"
|
|
233
|
+
title="动态加载与热更新"
|
|
234
|
+
lead="Fluxion 按 mtime + size 识别版本,避免重启进程。"
|
|
235
|
+
>
|
|
236
|
+
<div class="grid-two">
|
|
237
|
+
<article class="panel">
|
|
238
|
+
<h3 class="panel-title">Handler 写法</h3>
|
|
239
|
+
<CodeBlock code={handlerCode} />
|
|
240
|
+
</article>
|
|
241
|
+
<article class="panel panel-positive">
|
|
242
|
+
<h3 class="panel-title">缓存机制</h3>
|
|
243
|
+
<CodeBlock code={cacheCode} />
|
|
244
|
+
</article>
|
|
245
|
+
</div>
|
|
246
|
+
</Section>
|
|
247
|
+
|
|
248
|
+
<Section
|
|
249
|
+
id="meta-api"
|
|
250
|
+
title="元接口(Meta API)"
|
|
251
|
+
lead="用于观测路由、健康检查和上传部署。"
|
|
252
|
+
>
|
|
253
|
+
<div class="grid-two">
|
|
254
|
+
<article class="panel">
|
|
255
|
+
<h3 class="panel-title">GET /_fluxion/routes</h3>
|
|
256
|
+
<p class="panel-note">返回当前用于 diff 的完整快照对象。</p>
|
|
257
|
+
<CodeBlock code={metaRoutesCode} />
|
|
258
|
+
</article>
|
|
259
|
+
<article class="panel">
|
|
260
|
+
<h3 class="panel-title">GET /_fluxion/healthz</h3>
|
|
261
|
+
<p class="panel-note">健康检查接口,返回 ok 与当前时间戳。</p>
|
|
262
|
+
<CodeBlock code={healthzCode} />
|
|
263
|
+
</article>
|
|
264
|
+
</div>
|
|
265
|
+
</Section>
|
|
266
|
+
|
|
267
|
+
<Section
|
|
268
|
+
id="upload"
|
|
269
|
+
title="上传接口与解压判定"
|
|
270
|
+
lead="POST /_fluxion/upload 用于在线发布 tar 包,不支持 zip。"
|
|
271
|
+
>
|
|
272
|
+
<div class="grid-two">
|
|
273
|
+
<article class="panel">
|
|
274
|
+
<h3 class="panel-title">调用示例</h3>
|
|
275
|
+
<CodeBlock code={uploadCode} />
|
|
276
|
+
<p class="panel-note">
|
|
277
|
+
文件名可通过 query 参数 <code class="inline-code">filename</code> 或请求头
|
|
278
|
+
<code class="inline-code">x-fluxion-filename</code> 提供。
|
|
279
|
+
</p>
|
|
280
|
+
</article>
|
|
281
|
+
<article class="panel">
|
|
282
|
+
<h3 class="panel-title">解压判定规则</h3>
|
|
283
|
+
<CodeBlock code={uploadRuleCode} />
|
|
284
|
+
</article>
|
|
285
|
+
</div>
|
|
286
|
+
</Section>
|
|
287
|
+
|
|
288
|
+
<Section
|
|
289
|
+
id="examples"
|
|
290
|
+
title="访问示例速查"
|
|
291
|
+
lead="下面是最常见的路径到行为映射,便于快速排错。"
|
|
292
|
+
>
|
|
293
|
+
<div class="panel">
|
|
294
|
+
<CodeBlock code={requestMapCode} />
|
|
295
|
+
</div>
|
|
296
|
+
</Section>
|
|
297
|
+
</main>
|
|
298
|
+
|
|
299
|
+
<footer class="footer">
|
|
300
|
+
<p>Fluxion 文档页(kt.js + Vite)</p>
|
|
301
|
+
</footer>
|
|
302
|
+
</div>
|
|
303
|
+
);
|
|
304
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface SectionProps {
|
|
2
|
+
id: string;
|
|
3
|
+
title: string;
|
|
4
|
+
lead: string;
|
|
5
|
+
children?: any;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export function Section(props: SectionProps) {
|
|
9
|
+
return (
|
|
10
|
+
<section id={props.id} class="doc-section">
|
|
11
|
+
<header class="section-header">
|
|
12
|
+
<h2 class="section-title">{props.title}</h2>
|
|
13
|
+
<p class="section-lead">{props.lead}</p>
|
|
14
|
+
</header>
|
|
15
|
+
{props.children}
|
|
16
|
+
</section>
|
|
17
|
+
);
|
|
18
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
import { defineConfig } from 'vite';
|
|
4
|
+
import ktjsx from '@ktjs/vite-plugin-ktjsx';
|
|
5
|
+
|
|
6
|
+
const rootDir = import.meta.dirname;
|
|
7
|
+
|
|
8
|
+
export default defineConfig({
|
|
9
|
+
root: rootDir,
|
|
10
|
+
build: {
|
|
11
|
+
outDir: path.join(rootDir, 'dist'),
|
|
12
|
+
emptyOutDir: true,
|
|
13
|
+
},
|
|
14
|
+
esbuild: {
|
|
15
|
+
jsx: 'automatic',
|
|
16
|
+
jsxImportSource: 'kt.js',
|
|
17
|
+
},
|
|
18
|
+
plugins: [ktjsx()],
|
|
19
|
+
server: {
|
|
20
|
+
port: 4173,
|
|
21
|
+
open: true,
|
|
22
|
+
},
|
|
23
|
+
});
|
package/draft/vibe.md
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
请以http包、findmyway包,制作一个非常简单的服务器,要求:
|
|
2
|
+
|
|
3
|
+
1. 配置如下。
|
|
4
|
+
|
|
5
|
+
```json
|
|
6
|
+
{
|
|
7
|
+
"dynamicDirectory": "string",
|
|
8
|
+
"host": "string",
|
|
9
|
+
"port": "number"
|
|
10
|
+
}
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
2. dynamicDirectory用来指定一个目录,这个目录下的代码结构为:
|
|
14
|
+
|
|
15
|
+
```text
|
|
16
|
+
dynamicDirectory
|
|
17
|
+
└─somemodule
|
|
18
|
+
├── server
|
|
19
|
+
│ ├── index.js
|
|
20
|
+
└── web
|
|
21
|
+
├── index.html
|
|
22
|
+
└── style.css/main.js ...
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
3. dynamicDirectory是核心。服务器fs.watch这个目录.当这个目录下的文件变化,会触发diff。对于新增的somemodule,会将web下的内容注册为
|
|
26
|
+
router `/somemodule/...`,而server的路由注册为`/somemodule/api`。 不见了的文件夹,则删除这两个路由。你暂时不需要处理web静态资源问题,先把路由注册和删除做好。
|
|
27
|
+
|
|
28
|
+
4. 在开始的时候,服务器会扫描dynamicDirectory下的所有somemodule,并注册路由。
|
|
29
|
+
5. 增加一个输出jsonline日志的机制。不过,路由的注册可以用oneline那种日志,比如
|
|
30
|
+
|
|
31
|
+
```
|
|
32
|
+
[timestamp] [INFO] Registered route: /somemodule/
|
|
33
|
+
[timestamp] [INFO] Unregistered route: /somemodule/
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
你记住现在我们的项目叫fluxion,可以写在AGENTS.md里。我希望的是,假如我访问了/aaa/bb/cc这个路由,那么fluxion会寻找dynamicDirectory下的aaa文件夹里的server里的bb文件夹里的cc.js文件或者cc/index.js(优先)文件,以里面的函数作为handler来处理这个请求。这个函数的签名是`(req, res) => {}`,你可以在里面写任何逻辑来处理请求和响应。我不知道await import(xxx)能否胜任以及它缓存是否原生,或者是否有性能问题。我希望的是加载这个js文件的default导出。
|
|
39
|
+
请你评估这个方案
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
worker优化:
|
|
44
|
+
1、直接从worker返回你说的buffer来限制大小、判定,减少拷贝传输成本避免内存膨胀;
|
|
45
|
+
2、mjs编写的时候可以选择自己需要远程的什么对象,比如{handler,db:['pg','xxxDB']}等;handler里会传入第三个入参context来包含这些功能;
|
|
46
|
+
3、实现workerstrategy这个方案。
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
现在,请你把db config的interface保留下来。我已经删除了pg和mysql2依赖,因为它们不应该这样写,它们应该在用户npm install fluxion后由用户自行安装引入,fluxion只做配置传递。为不失一般性,mjs返回的不再是db:{key:value},而是modules:[{module:'mysql2',injectKey:"mydb",factory:(...)=>{ 这里返回最终注入context的对象}}]。而这个modules数组将会传输到worker,其中,factory因为是函数,所以会tostring后传输,传输到worker内部后再new Function的形式绕回来,而最终这个数据库链接实例会出现在context.mydb。
|
package/package.json
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "fluxion-ts",
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"author": {
|
|
5
|
+
"name": "Kasukabe Tsumugi",
|
|
6
|
+
"email": "futami16237@gmail.com"
|
|
7
|
+
},
|
|
8
|
+
"purpose": "npm",
|
|
9
|
+
"description": "Fluxion is able to start a server that can dynamically load routers and js files. It is designed to be used to replace PHP",
|
|
10
|
+
"description_zh": "Fluxion可以启动一个能够动态加载路由和js文件的服务器,旨在替代PHP",
|
|
11
|
+
"type": "module",
|
|
12
|
+
"homepage": "https://github.com/baendlorel/fluxion#readme",
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "https://github.com/baendlorel/fluxion"
|
|
16
|
+
},
|
|
17
|
+
"keywords": [
|
|
18
|
+
"framework",
|
|
19
|
+
"server",
|
|
20
|
+
"typescript",
|
|
21
|
+
"javascript"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@ktjs/ts-plugin": "^0.1.13",
|
|
26
|
+
"@ktjs/vite-plugin-ktjsx": "^0.4.3",
|
|
27
|
+
"@rollup/plugin-commonjs": "^29.0.0",
|
|
28
|
+
"@rollup/plugin-json": "^6.1.0",
|
|
29
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
30
|
+
"@rollup/plugin-replace": "^6.0.3",
|
|
31
|
+
"@rollup/plugin-terser": "^0.4.4",
|
|
32
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
33
|
+
"@types/node": "^25.3.2",
|
|
34
|
+
"axios": "^1.13.6",
|
|
35
|
+
"kt.js": "^0.31.4",
|
|
36
|
+
"oxlint": "^1.50.0",
|
|
37
|
+
"prettier": "^3.8.1",
|
|
38
|
+
"rimraf": "^6.1.3",
|
|
39
|
+
"rollup": "4.59.0",
|
|
40
|
+
"rollup-plugin-conditional-compilation": "^2.1.2",
|
|
41
|
+
"rollup-plugin-dts": "^6.3.0",
|
|
42
|
+
"rollup-plugin-func-macro": "^1.2.2",
|
|
43
|
+
"tslib": "^2.8.1",
|
|
44
|
+
"tsx": "^4.21.0",
|
|
45
|
+
"typescript": "^5.9.3",
|
|
46
|
+
"vite": "^7.3.1",
|
|
47
|
+
"vitest": "^4.0.18"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"chalk": "^5.6.2",
|
|
51
|
+
"find-my-way": "^9.5.0"
|
|
52
|
+
},
|
|
53
|
+
"scripts": {
|
|
54
|
+
"start": "code-server --bind-addr 0.0.0.0:3000 /app/dynamic && node /app/index.js",
|
|
55
|
+
"dev": "tsx ./src/index.ts --watch",
|
|
56
|
+
"exp": "vite dev --config document/vite.config.ts",
|
|
57
|
+
"lines": "tsx ./scripts/lines.ts",
|
|
58
|
+
"doc:dev": "vite --config document/vite.config.ts",
|
|
59
|
+
"doc:build": "vite build --config document/vite.config.ts",
|
|
60
|
+
"image": "tsx ./scripts/build-image.ts",
|
|
61
|
+
"build": "rollup -c",
|
|
62
|
+
"pub": "tsx ./scripts/publish.ts",
|
|
63
|
+
"test": "vitest",
|
|
64
|
+
"lint": "oxlint ."
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
|
|
4
|
+
import { rimraf } from 'rimraf';
|
|
5
|
+
import resolve from '@rollup/plugin-node-resolve';
|
|
6
|
+
import json from '@rollup/plugin-json';
|
|
7
|
+
import commonjs from '@rollup/plugin-commonjs';
|
|
8
|
+
import typescript from '@rollup/plugin-typescript';
|
|
9
|
+
import terser from '@rollup/plugin-terser';
|
|
10
|
+
import replace from '@rollup/plugin-replace';
|
|
11
|
+
import dts from 'rollup-plugin-dts';
|
|
12
|
+
|
|
13
|
+
export default async (_commandLineArgs) => {
|
|
14
|
+
const libPath = import.meta.dirname;
|
|
15
|
+
|
|
16
|
+
await rimraf(path.join(libPath, 'dist'));
|
|
17
|
+
return [
|
|
18
|
+
{
|
|
19
|
+
input: path.join(libPath, 'src', 'index.ts'),
|
|
20
|
+
output: [
|
|
21
|
+
{
|
|
22
|
+
file: path.join(libPath, 'dist', 'index.mjs'),
|
|
23
|
+
format: 'esm', // ES module output
|
|
24
|
+
sourcemap: true,
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
plugins: [
|
|
28
|
+
typescript({ tsconfig: './tsconfig.json' }),
|
|
29
|
+
resolve(),
|
|
30
|
+
json(),
|
|
31
|
+
commonjs(),
|
|
32
|
+
replace(replaceOpts(libPath)),
|
|
33
|
+
void terser(),
|
|
34
|
+
].filter(Boolean),
|
|
35
|
+
external: [/^node:/],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
input: path.join(libPath, 'src', 'index.ts'),
|
|
39
|
+
output: [{ file: path.join(libPath, 'dist', 'index.d.ts'), format: 'es' }],
|
|
40
|
+
plugins: [dts({ tsconfig: './tsconfig.json' })],
|
|
41
|
+
external: [/^node:/],
|
|
42
|
+
},
|
|
43
|
+
];
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
// #region replace options
|
|
47
|
+
|
|
48
|
+
export const globalDefines = {
|
|
49
|
+
'process.env.NODE_ENV': '"production"',
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export function replaceOpts(packagePath) {
|
|
53
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(packagePath, 'package.json'), 'utf-8'));
|
|
54
|
+
function formatDateFull(dt = new Date()) {
|
|
55
|
+
const y = dt.getFullYear();
|
|
56
|
+
const m = String(dt.getMonth() + 1).padStart(2, '0');
|
|
57
|
+
const d = String(dt.getDate()).padStart(2, '0');
|
|
58
|
+
const hh = String(dt.getHours()).padStart(2, '0');
|
|
59
|
+
const mm = String(dt.getMinutes()).padStart(2, '0');
|
|
60
|
+
const ss = String(dt.getSeconds()).padStart(2, '0');
|
|
61
|
+
const ms = String(dt.getMilliseconds()).padStart(3, '0');
|
|
62
|
+
return `${y}.${m}.${d} ${hh}:${mm}:${ss}.${ms}`;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const __KEBAB_NAME__ = pkg.name.replace('rollup-plugin-', '');
|
|
66
|
+
const __VERSION__ = pkg.version;
|
|
67
|
+
const __NAME__ = __KEBAB_NAME__.replace(/(^|-)(\w)/g, (_, __, c) => c.toUpperCase());
|
|
68
|
+
|
|
69
|
+
const __PKG_INFO__ = `## About
|
|
70
|
+
* @package ${__NAME__}
|
|
71
|
+
* @author ${pkg.author.name} <${pkg.author.email}>
|
|
72
|
+
* @version ${pkg.version} (Last Update: ${formatDateFull()})
|
|
73
|
+
* @license ${pkg.license}
|
|
74
|
+
* @link ${pkg.repository.url}
|
|
75
|
+
* @link https://baendlorel.github.io/ Welcome to my site!
|
|
76
|
+
* @description ${pkg.description.replace(/\n/g, '\n * \n * ')}
|
|
77
|
+
* @copyright Copyright (c) ${new Date().getFullYear()} ${pkg.author.name}. All rights reserved.`;
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
preventAssignment: true,
|
|
81
|
+
delimiters: ['', ''],
|
|
82
|
+
values: {
|
|
83
|
+
__IS_DEV__: 'false',
|
|
84
|
+
__NAME__,
|
|
85
|
+
__KEBAB_NAME__,
|
|
86
|
+
__PKG_INFO__,
|
|
87
|
+
__VERSION__,
|
|
88
|
+
|
|
89
|
+
// global flags
|
|
90
|
+
...globalDefines,
|
|
91
|
+
|
|
92
|
+
// global error/warn/debug
|
|
93
|
+
"$throw('": `throw new Error('[${__NAME__} error] `,
|
|
94
|
+
'$throw(`': `throw new Error(\`[${__NAME__} error] `,
|
|
95
|
+
'$throw("': `throw new Error("[${__NAME__} error] `,
|
|
96
|
+
'$warn(': `console.warn('[${__NAME__} warn]',`,
|
|
97
|
+
'$error(': `console.error('[${__NAME__} error]',`,
|
|
98
|
+
'$debug(': `console.debug('[${__NAME__} debug]',`,
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
// #endregion
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { bumpVersion } from './bump-version';
|
|
5
|
+
|
|
6
|
+
const pkgPath = path.resolve(import.meta.dirname, '..', '.image.json');
|
|
7
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { name: string; version: string };
|
|
8
|
+
const imageName = `${pkg.name}:${pkg.version}`;
|
|
9
|
+
|
|
10
|
+
execSync('pnpm build', { stdio: 'inherit' });
|
|
11
|
+
execSync(`docker build -t ${imageName} .`, { stdio: 'inherit' });
|
|
12
|
+
|
|
13
|
+
bumpVersion(pkgPath);
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
export function bumpVersion(pkgPath: string = path.resolve(import.meta.dirname, '..', 'package.json')) {
|
|
5
|
+
const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8')) as { name: string; version: string };
|
|
6
|
+
const [major, minor, patch] = pkg.version.split('.').map(Number);
|
|
7
|
+
const nextVersion = [major, minor, patch + 1].join('.');
|
|
8
|
+
const oldVersion = pkg.version;
|
|
9
|
+
pkg.version = nextVersion;
|
|
10
|
+
writeFileSync(pkgPath, JSON.stringify(pkg, null, 2) + '\n');
|
|
11
|
+
console.log(`Bumped version: ${oldVersion} -> ${nextVersion}`);
|
|
12
|
+
}
|