oipage 1.7.0-alpha.7 → 1.7.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/.github/FUNDING.yml +11 -11
- package/AUTHORS.txt +6 -6
- package/CHANGELOG +156 -159
- package/LICENSE +20 -20
- package/README.md +95 -95
- package/bin/WebSocket/decodeWsFrame.js +43 -43
- package/bin/WebSocket/encodeWsFrame.js +28 -28
- package/bin/WebSocket/headersToJSON.js +26 -26
- package/bin/WebSocket/index.js +80 -80
- package/bin/data/mineTypes.json +104 -104
- package/bin/disk.js +42 -42
- package/bin/help.js +45 -45
- package/bin/intercept.js +15 -15
- package/bin/network.js +21 -21
- package/bin/proxy.js +75 -75
- package/bin/run +129 -129
- package/bin/serve.d.ts +64 -64
- package/bin/serve.js +179 -179
- package/bin/template/404.html +186 -186
- package/bin/tools/deleteEmptyFolder.js +23 -23
- package/bin/tools/format.js +75 -75
- package/bin/tools/network.js +42 -42
- package/bin/tools/resolve404.js +83 -83
- package/bin/tools/resolveImport.js +88 -88
- package/bin/website-htmls/components/ui-select-file/index.html +7 -7
- package/bin/website-htmls/components/ui-select-file/index.js +37 -37
- package/bin/website-htmls/components/ui-select-file/index.scss +44 -44
- package/bin/website-htmls/dialogs/imageSize/index.html +54 -54
- package/bin/website-htmls/dialogs/imageSize/index.js +53 -53
- package/bin/website-htmls/dialogs/imageSize/index.scss +138 -138
- package/bin/website-htmls/dialogs/index.js +52 -52
- package/bin/website-htmls/images/addFile.svg +1 -1
- package/bin/website-htmls/images/img-to-pdf.svg +1 -1
- package/bin/website-htmls/index.html +17 -17
- package/bin/website-htmls/main.js +13 -13
- package/bin/website-htmls/pages/App/index.html +6 -6
- package/bin/website-htmls/pages/App/index.js +22 -22
- package/bin/website-htmls/pages/App/index.scss +43 -43
- package/bin/website-htmls/pages/appStore/index.html +24 -24
- package/bin/website-htmls/pages/appStore/index.js +19 -19
- package/bin/website-htmls/pages/appStore/index.scss +41 -41
- package/bin/website-htmls/pages/chart/index.html +8 -8
- package/bin/website-htmls/pages/chart/index.js +72 -72
- package/bin/website-htmls/pages/chart/index.scss +72 -72
- package/bin/website-htmls/pages/image-editor/index.html +27 -27
- package/bin/website-htmls/pages/image-editor/index.js +106 -106
- package/bin/website-htmls/pages/image-editor/index.scss +45 -45
- package/bin/website-htmls/pages/img-to-pdf/index.html +3 -3
- package/bin/website-htmls/pages/img-to-pdf/index.js +44 -44
- package/bin/website-htmls/pages/img-to-pdf/index.scss +4 -4
- package/bin/website-htmls/router.config.js +19 -19
- package/bin/website-htmls/styles/normalize.css +94 -94
- package/bin/website-plugins/intercept/chart.js +33 -33
- package/bin/website-plugins/intercept/getPackage.js +17 -17
- package/bin/website-plugins/intercept/head.js +8 -8
- package/bin/website-plugins/intercept/index.js +8 -8
- package/bin/website-plugins/intercept/oipage-vislite-intercept.js +30 -30
- package/bin/website-plugins/intercept/oipage-zipaper-intercept.js +36 -36
- package/bin/website-plugins/loader/index.js +11 -11
- package/bin/website-plugins/loader/oipage-html-loader.js +7 -7
- package/bin/website-plugins/loader/oipage-scss-loader.js +149 -149
- package/nodejs/animation/index.d.ts +19 -19
- package/nodejs/animation/index.js +112 -112
- package/nodejs/cmdlog/index.d.ts +20 -20
- package/nodejs/cmdlog/index.js +75 -75
- package/nodejs/disk/index.d.ts +47 -47
- package/nodejs/disk/index.js +165 -165
- package/nodejs/format/index.d.ts +29 -29
- package/nodejs/format/index.js +107 -107
- package/nodejs/json/index.d.ts +9 -9
- package/nodejs/json/index.js +206 -206
- package/nodejs/logform/index.d.ts +18 -18
- package/nodejs/logform/index.js +94 -94
- package/nodejs/reader/index.d.ts +32 -32
- package/nodejs/reader/index.js +20 -20
- package/nodejs/throttle/index.d.ts +30 -30
- package/nodejs/throttle/index.js +50 -50
- package/package.json +45 -45
- package/types/index.d.ts +2 -4
- package/web/XMLHttpRequest/index.d.ts +17 -17
- package/web/XMLHttpRequest/index.js +60 -60
- package/web/animation/index.d.ts +19 -19
- package/web/animation/index.js +112 -112
- package/web/format/index.d.ts +29 -29
- package/web/format/index.js +107 -107
- package/web/json/index.d.ts +9 -9
- package/web/json/index.js +206 -206
- package/web/onReady/index.d.ts +7 -7
- package/web/onReady/index.js +8 -8
- package/web/performChunk/index.d.ts +4 -4
- package/web/performChunk/index.js +19 -19
- package/web/reader/index.d.ts +32 -32
- package/web/reader/index.js +20 -20
- package/web/style/index.d.ts +21 -21
- package/web/style/index.js +19 -19
- package/web/throttle/index.d.ts +30 -30
- package/web/throttle/index.js +50 -50
- package/nodejs/remote/index.d.ts +0 -39
- package/nodejs/remote/index.js +0 -91
package/bin/serve.d.ts
CHANGED
|
@@ -1,65 +1,65 @@
|
|
|
1
|
-
|
|
2
|
-
interface DevServerType {
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* 服务器端口号
|
|
6
|
-
*/
|
|
7
|
-
port: number
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* 服务器根路径
|
|
11
|
-
*/
|
|
12
|
-
baseUrl: string
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* 是否开启304缓存,默认开启
|
|
16
|
-
*/
|
|
17
|
-
cache: boolean
|
|
18
|
-
|
|
19
|
-
intercept?: Array<InterceptType>
|
|
20
|
-
|
|
21
|
-
proxy?: {
|
|
22
|
-
[key: string]: {
|
|
23
|
-
target: string
|
|
24
|
-
pathRewrite?: {
|
|
25
|
-
[key: string]: string
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
interface InterceptType {
|
|
32
|
-
test: RegExp
|
|
33
|
-
handler(request: any, response: any): void
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
interface LoaderType {
|
|
37
|
-
(source: string): string
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
interface ConfigType {
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* 服务器名称
|
|
44
|
-
*/
|
|
45
|
-
name?: string
|
|
46
|
-
|
|
47
|
-
/**
|
|
48
|
-
* 服务器版本
|
|
49
|
-
*/
|
|
50
|
-
version?: string
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* 服务器运行配置
|
|
54
|
-
*/
|
|
55
|
-
devServer: DevServerType
|
|
56
|
-
|
|
57
|
-
module?: {
|
|
58
|
-
rules: Array<{
|
|
59
|
-
test: RegExp
|
|
60
|
-
use: LoaderType
|
|
61
|
-
}>
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
1
|
+
|
|
2
|
+
interface DevServerType {
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 服务器端口号
|
|
6
|
+
*/
|
|
7
|
+
port: number
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* 服务器根路径
|
|
11
|
+
*/
|
|
12
|
+
baseUrl: string
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 是否开启304缓存,默认开启
|
|
16
|
+
*/
|
|
17
|
+
cache: boolean
|
|
18
|
+
|
|
19
|
+
intercept?: Array<InterceptType>
|
|
20
|
+
|
|
21
|
+
proxy?: {
|
|
22
|
+
[key: string]: {
|
|
23
|
+
target: string
|
|
24
|
+
pathRewrite?: {
|
|
25
|
+
[key: string]: string
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
interface InterceptType {
|
|
32
|
+
test: RegExp
|
|
33
|
+
handler(request: any, response: any): void
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
interface LoaderType {
|
|
37
|
+
(source: string): string
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
interface ConfigType {
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 服务器名称
|
|
44
|
+
*/
|
|
45
|
+
name?: string
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* 服务器版本
|
|
49
|
+
*/
|
|
50
|
+
version?: string
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* 服务器运行配置
|
|
54
|
+
*/
|
|
55
|
+
devServer: DevServerType
|
|
56
|
+
|
|
57
|
+
module?: {
|
|
58
|
+
rules: Array<{
|
|
59
|
+
test: RegExp
|
|
60
|
+
use: LoaderType
|
|
61
|
+
}>
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
65
|
export default function (config?: ConfigType): void
|
package/bin/serve.js
CHANGED
|
@@ -1,180 +1,180 @@
|
|
|
1
|
-
const { join } = require("path");
|
|
2
|
-
const { existsSync, lstatSync, statSync, createReadStream } = require("fs");
|
|
3
|
-
const { createServer } = require('http');
|
|
4
|
-
const packageValue = require("../package.json");
|
|
5
|
-
const network = require("./tools/network.js");
|
|
6
|
-
const mineTypes = require("./data/mineTypes.json");
|
|
7
|
-
const resolve404 = require("./tools/resolve404.js");
|
|
8
|
-
const resolveImportFactory = require("./tools/resolveImport.js");
|
|
9
|
-
const { doIntercept } = require("./intercept.js");
|
|
10
|
-
const proxy = require("./proxy.js");
|
|
11
|
-
|
|
12
|
-
const websiteIntercept = require("./website-plugins/intercept/index.js");
|
|
13
|
-
const websiteLoader = require("./website-plugins/loader/index.js");
|
|
14
|
-
|
|
15
|
-
const WebSocketClass = require("./WebSocket/index.js");
|
|
16
|
-
|
|
17
|
-
// 开发服务器
|
|
18
|
-
module.exports = function (config) {
|
|
19
|
-
let startTime = new Date().valueOf();
|
|
20
|
-
|
|
21
|
-
const cache = "cache" in config.devServer ? config.devServer.cache : true;
|
|
22
|
-
const port = +config.devServer.port; // 端口号
|
|
23
|
-
const basePath = (/^\./.test(config.devServer.baseUrl)) ? join(process.cwd(), config.devServer.baseUrl) : config.devServer.baseUrl; // 服务器根路径
|
|
24
|
-
|
|
25
|
-
const name = (config.name || "OIPage") + "-http-server";
|
|
26
|
-
const version = config.version || packageValue.version;
|
|
27
|
-
|
|
28
|
-
const wsHandler = WebSocketClass(port + 1, (config.name || "OIPage") + "-ws-server", version);
|
|
29
|
-
|
|
30
|
-
let Server = createServer(function (request, response) {
|
|
31
|
-
let headers = request.headers;
|
|
32
|
-
let url = decodeURIComponent(request.url);
|
|
33
|
-
|
|
34
|
-
let urlArray = url.split("?");
|
|
35
|
-
url = urlArray[0];
|
|
36
|
-
|
|
37
|
-
// 请求的文件路径
|
|
38
|
-
let filePath;
|
|
39
|
-
|
|
40
|
-
let isWebsite = /^\/_oipage_website_\//.test(url);
|
|
41
|
-
if (isWebsite) {
|
|
42
|
-
filePath = join(__dirname, "./website-htmls/", url.replace(/^\/_oipage_website_\//, ""));
|
|
43
|
-
} else {
|
|
44
|
-
filePath = join(basePath, url == "/" ? "index.html" : url.replace(/^\//, ""));
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
let proxyIntercept = proxy({
|
|
48
|
-
name,
|
|
49
|
-
version
|
|
50
|
-
}, config.devServer.proxy || {});
|
|
51
|
-
delete config.devServer.proxy;
|
|
52
|
-
for (let i = 0; i < proxyIntercept.length; i++) {
|
|
53
|
-
config.devServer.intercept.push(proxyIntercept[i]);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// 请求拦截
|
|
57
|
-
if (doIntercept(url.replace(/^\/_oipage_website_/, "").replace(/^\/@modules\//, ""), isWebsite ? websiteIntercept : config.devServer.intercept, request, response, wsHandler)) {
|
|
58
|
-
console.log("<i> \x1b[1m\x1b[32m[" + name + "] intercept: " + url + '\x1b[0m ' + new Date().toLocaleString());
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
// 如果存在且是文件
|
|
62
|
-
else if (existsSync(filePath) && !lstatSync(filePath).isDirectory()) {
|
|
63
|
-
|
|
64
|
-
// 判断是否是请求而无需进一步解析
|
|
65
|
-
// 2025年12月5日 于南京
|
|
66
|
-
let isXHR = headers["sec-fetch-dest"] === "empty";
|
|
67
|
-
|
|
68
|
-
let dotName = /\./.test(filePath) ? filePath.match(/\.([^.]+)$/)[1] : "";
|
|
69
|
-
let fileType = mineTypes[dotName]; // 文件类型
|
|
70
|
-
let fileInfo = statSync(filePath);
|
|
71
|
-
|
|
72
|
-
let fileModifiedTime = new Date(fileInfo.mtime).toGMTString();
|
|
73
|
-
|
|
74
|
-
let responseHeader = {
|
|
75
|
-
'Content-Type': (fileType || "text/plain") + ";charset=utf-8",
|
|
76
|
-
'Access-Control-Allow-Origin': '*',
|
|
77
|
-
'Server': 'Powered by ' + name + '@' + version,
|
|
78
|
-
'Cache-Control': 'no-cache',
|
|
79
|
-
// 'Content-Length': fileInfo.size, // 会导致拦截修改的文本内容不对
|
|
80
|
-
|
|
81
|
-
// 与if-modified-since配合使用,做缓存验证
|
|
82
|
-
'Last-Modified': fileModifiedTime,
|
|
83
|
-
|
|
84
|
-
// 与if-none-match配合使用,做缓存验证
|
|
85
|
-
// 'ETag': basePath + "-" + new Date(fileInfo.mtime).toString()
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
if (cache && headers["if-modified-since"]) {
|
|
89
|
-
let ifModifiedSince = new Date(headers["if-modified-since"]).valueOf()
|
|
90
|
-
let lastModified = new Date(fileModifiedTime).valueOf()
|
|
91
|
-
|
|
92
|
-
// 注意这里不能使用<=,否则
|
|
93
|
-
// 1、会出现时区问题
|
|
94
|
-
// 2、作为开发服务器,可能同一个url地址对应的文件不同,被误判为未修改
|
|
95
|
-
// 2025年12月29日 于南京
|
|
96
|
-
// if (lastModified <= ifModifiedSince) {}
|
|
97
|
-
if (lastModified === ifModifiedSince) {
|
|
98
|
-
response.writeHead('304', responseHeader);
|
|
99
|
-
response.end();
|
|
100
|
-
console.log("<i> \x1b[1m\x1b[32m[" + name + "] Cache File: " + url + "\x1b[0m " + new Date().toLocaleString() + "\x1b[33m\x1b[1m 304" + (isXHR ? " 请求" : "") + "\x1b[0m");
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
let sendType = "";
|
|
106
|
-
let entry = headers.accept !== "*/*";
|
|
107
|
-
|
|
108
|
-
// 如果文件小于10M,认为不大,直接读取
|
|
109
|
-
if (fileInfo.size < 10 * 1024 * 1024) {
|
|
110
|
-
let { source, resolveImport } = resolveImportFactory(basePath, filePath, entry, isWebsite ? websiteIntercept : config.devServer.intercept, urlArray[1] === "download", isWebsite)
|
|
111
|
-
|
|
112
|
-
// 只处理非下载文件
|
|
113
|
-
// 过大的也不进行处理
|
|
114
|
-
// (对website无效)
|
|
115
|
-
if (urlArray[1] !== "download") {
|
|
116
|
-
let loaders = isWebsite ? websiteLoader : config.module;
|
|
117
|
-
|
|
118
|
-
for (let i = 0; i < loaders.rules.length; i++) {
|
|
119
|
-
if (loaders.rules[i].test.test(filePath)) {
|
|
120
|
-
source = loaders.rules[i].use.call({
|
|
121
|
-
root: basePath, // 服务器根路径
|
|
122
|
-
path: filePath.replace(basePath, ""), // 文件相对路径
|
|
123
|
-
entry, // 是否是浏览器地址栏直接访问
|
|
124
|
-
setFileType(_fileType) { // 设置文件类型
|
|
125
|
-
fileType = _fileType;
|
|
126
|
-
responseHeader['Content-Type'] = _fileType + ";charset=utf-8";
|
|
127
|
-
}
|
|
128
|
-
}, source);
|
|
129
|
-
break;
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
sendType = "Read";
|
|
136
|
-
response.writeHead('200', responseHeader);
|
|
137
|
-
response.write(isXHR ? source : resolveImport(source, fileType !== "application/javascript"));
|
|
138
|
-
response.end();
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
// 对于大文件,使用流读取
|
|
142
|
-
else {
|
|
143
|
-
sendType = "Stream";
|
|
144
|
-
|
|
145
|
-
responseHeader['Content-Length'] = fileInfo.size
|
|
146
|
-
|
|
147
|
-
response.writeHead('200', responseHeader);
|
|
148
|
-
createReadStream(filePath).pipe(response);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
console.log("<i> \x1b[1m\x1b[32m[" + name + "] " + sendType + " File: " + url + '\x1b[0m ' + new Date().toLocaleString() + "\x1b[33m\x1b[1m" + (isXHR ? " 请求" : "") + "\x1b[0m");
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
// 否则就是404
|
|
155
|
-
else {
|
|
156
|
-
response.writeHead(404, {
|
|
157
|
-
'Content-Type': "text/html;charset=utf-8",
|
|
158
|
-
'Access-Control-Allow-Origin': '*',
|
|
159
|
-
'Server': 'Powered by ' + name + '@' + version
|
|
160
|
-
});
|
|
161
|
-
response.write(resolve404(filePath, url));
|
|
162
|
-
response.end();
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
Server.listen(port);
|
|
168
|
-
|
|
169
|
-
// 获取网络信息
|
|
170
|
-
let networkValue = network();
|
|
171
|
-
|
|
172
|
-
// 打印成功提示
|
|
173
|
-
console.log('<i> \x1b[1m\x1b[32m[' + name + '] Project is running at:\x1b[0m');
|
|
174
|
-
console.log('<i> \x1b[1m\x1b[32m[' + name + '] Loopback: \x1b[36mhttp://localhost:' + port + '/\x1b[0m');
|
|
175
|
-
for (let ipv4Item of networkValue.IPv4) console.log('<i> \x1b[1m\x1b[32m[' + name + '] On Your Network (IPv4):\x1b[36m http://' + ipv4Item.address + ':' + port + '/\x1b[0m');
|
|
176
|
-
for (let ipv6Item of networkValue.IPv6) console.log('<i> \x1b[1m\x1b[32m[' + name + '] On Your Network (IPv6): \x1b[36mhttp://[' + ipv6Item.address + ']:' + port + '/\x1b[0m');
|
|
177
|
-
console.log('<i> \x1b[1m\x1b[32m[' + name + '] Content not from ' + (config.name || "OIPage") + ' is served from \x1b[36m"' + basePath + '" \x1b[0mdirectory');
|
|
178
|
-
if (!cache) console.log('<i> \x1b[1m\x1b[32m[' + name + '] Cancel 304 Cache!\x1b[0m');
|
|
179
|
-
console.log('\n' + (config.name || "OIPage") + ' ' + version + ' compiled \x1b[1m\x1b[32msuccessfully\x1b[0m in ' + (new Date().valueOf() - startTime) + ' ms\n')
|
|
1
|
+
const { join } = require("path");
|
|
2
|
+
const { existsSync, lstatSync, statSync, createReadStream } = require("fs");
|
|
3
|
+
const { createServer } = require('http');
|
|
4
|
+
const packageValue = require("../package.json");
|
|
5
|
+
const network = require("./tools/network.js");
|
|
6
|
+
const mineTypes = require("./data/mineTypes.json");
|
|
7
|
+
const resolve404 = require("./tools/resolve404.js");
|
|
8
|
+
const resolveImportFactory = require("./tools/resolveImport.js");
|
|
9
|
+
const { doIntercept } = require("./intercept.js");
|
|
10
|
+
const proxy = require("./proxy.js");
|
|
11
|
+
|
|
12
|
+
const websiteIntercept = require("./website-plugins/intercept/index.js");
|
|
13
|
+
const websiteLoader = require("./website-plugins/loader/index.js");
|
|
14
|
+
|
|
15
|
+
const WebSocketClass = require("./WebSocket/index.js");
|
|
16
|
+
|
|
17
|
+
// 开发服务器
|
|
18
|
+
module.exports = function (config) {
|
|
19
|
+
let startTime = new Date().valueOf();
|
|
20
|
+
|
|
21
|
+
const cache = "cache" in config.devServer ? config.devServer.cache : true;
|
|
22
|
+
const port = +config.devServer.port; // 端口号
|
|
23
|
+
const basePath = (/^\./.test(config.devServer.baseUrl)) ? join(process.cwd(), config.devServer.baseUrl) : config.devServer.baseUrl; // 服务器根路径
|
|
24
|
+
|
|
25
|
+
const name = (config.name || "OIPage") + "-http-server";
|
|
26
|
+
const version = config.version || packageValue.version;
|
|
27
|
+
|
|
28
|
+
const wsHandler = WebSocketClass(port + 1, (config.name || "OIPage") + "-ws-server", version);
|
|
29
|
+
|
|
30
|
+
let Server = createServer(function (request, response) {
|
|
31
|
+
let headers = request.headers;
|
|
32
|
+
let url = decodeURIComponent(request.url);
|
|
33
|
+
|
|
34
|
+
let urlArray = url.split("?");
|
|
35
|
+
url = urlArray[0];
|
|
36
|
+
|
|
37
|
+
// 请求的文件路径
|
|
38
|
+
let filePath;
|
|
39
|
+
|
|
40
|
+
let isWebsite = /^\/_oipage_website_\//.test(url);
|
|
41
|
+
if (isWebsite) {
|
|
42
|
+
filePath = join(__dirname, "./website-htmls/", url.replace(/^\/_oipage_website_\//, ""));
|
|
43
|
+
} else {
|
|
44
|
+
filePath = join(basePath, url == "/" ? "index.html" : url.replace(/^\//, ""));
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
let proxyIntercept = proxy({
|
|
48
|
+
name,
|
|
49
|
+
version
|
|
50
|
+
}, config.devServer.proxy || {});
|
|
51
|
+
delete config.devServer.proxy;
|
|
52
|
+
for (let i = 0; i < proxyIntercept.length; i++) {
|
|
53
|
+
config.devServer.intercept.push(proxyIntercept[i]);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// 请求拦截
|
|
57
|
+
if (doIntercept(url.replace(/^\/_oipage_website_/, "").replace(/^\/@modules\//, ""), isWebsite ? websiteIntercept : config.devServer.intercept, request, response, wsHandler)) {
|
|
58
|
+
console.log("<i> \x1b[1m\x1b[32m[" + name + "] intercept: " + url + '\x1b[0m ' + new Date().toLocaleString());
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// 如果存在且是文件
|
|
62
|
+
else if (existsSync(filePath) && !lstatSync(filePath).isDirectory()) {
|
|
63
|
+
|
|
64
|
+
// 判断是否是请求而无需进一步解析
|
|
65
|
+
// 2025年12月5日 于南京
|
|
66
|
+
let isXHR = headers["sec-fetch-dest"] === "empty";
|
|
67
|
+
|
|
68
|
+
let dotName = /\./.test(filePath) ? filePath.match(/\.([^.]+)$/)[1] : "";
|
|
69
|
+
let fileType = mineTypes[dotName]; // 文件类型
|
|
70
|
+
let fileInfo = statSync(filePath);
|
|
71
|
+
|
|
72
|
+
let fileModifiedTime = new Date(fileInfo.mtime).toGMTString();
|
|
73
|
+
|
|
74
|
+
let responseHeader = {
|
|
75
|
+
'Content-Type': (fileType || "text/plain") + ";charset=utf-8",
|
|
76
|
+
'Access-Control-Allow-Origin': '*',
|
|
77
|
+
'Server': 'Powered by ' + name + '@' + version,
|
|
78
|
+
'Cache-Control': 'no-cache',
|
|
79
|
+
// 'Content-Length': fileInfo.size, // 会导致拦截修改的文本内容不对
|
|
80
|
+
|
|
81
|
+
// 与if-modified-since配合使用,做缓存验证
|
|
82
|
+
'Last-Modified': fileModifiedTime,
|
|
83
|
+
|
|
84
|
+
// 与if-none-match配合使用,做缓存验证
|
|
85
|
+
// 'ETag': basePath + "-" + new Date(fileInfo.mtime).toString()
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
if (cache && headers["if-modified-since"]) {
|
|
89
|
+
let ifModifiedSince = new Date(headers["if-modified-since"]).valueOf()
|
|
90
|
+
let lastModified = new Date(fileModifiedTime).valueOf()
|
|
91
|
+
|
|
92
|
+
// 注意这里不能使用<=,否则
|
|
93
|
+
// 1、会出现时区问题
|
|
94
|
+
// 2、作为开发服务器,可能同一个url地址对应的文件不同,被误判为未修改
|
|
95
|
+
// 2025年12月29日 于南京
|
|
96
|
+
// if (lastModified <= ifModifiedSince) {}
|
|
97
|
+
if (lastModified === ifModifiedSince) {
|
|
98
|
+
response.writeHead('304', responseHeader);
|
|
99
|
+
response.end();
|
|
100
|
+
console.log("<i> \x1b[1m\x1b[32m[" + name + "] Cache File: " + url + "\x1b[0m " + new Date().toLocaleString() + "\x1b[33m\x1b[1m 304" + (isXHR ? " 请求" : "") + "\x1b[0m");
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
let sendType = "";
|
|
106
|
+
let entry = headers.accept !== "*/*";
|
|
107
|
+
|
|
108
|
+
// 如果文件小于10M,认为不大,直接读取
|
|
109
|
+
if (fileInfo.size < 10 * 1024 * 1024) {
|
|
110
|
+
let { source, resolveImport } = resolveImportFactory(basePath, filePath, entry, isWebsite ? websiteIntercept : config.devServer.intercept, urlArray[1] === "download", isWebsite)
|
|
111
|
+
|
|
112
|
+
// 只处理非下载文件
|
|
113
|
+
// 过大的也不进行处理
|
|
114
|
+
// (对website无效)
|
|
115
|
+
if (urlArray[1] !== "download") {
|
|
116
|
+
let loaders = isWebsite ? websiteLoader : config.module;
|
|
117
|
+
|
|
118
|
+
for (let i = 0; i < loaders.rules.length; i++) {
|
|
119
|
+
if (loaders.rules[i].test.test(filePath)) {
|
|
120
|
+
source = loaders.rules[i].use.call({
|
|
121
|
+
root: basePath, // 服务器根路径
|
|
122
|
+
path: filePath.replace(basePath, ""), // 文件相对路径
|
|
123
|
+
entry, // 是否是浏览器地址栏直接访问
|
|
124
|
+
setFileType(_fileType) { // 设置文件类型
|
|
125
|
+
fileType = _fileType;
|
|
126
|
+
responseHeader['Content-Type'] = _fileType + ";charset=utf-8";
|
|
127
|
+
}
|
|
128
|
+
}, source);
|
|
129
|
+
break;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
sendType = "Read";
|
|
136
|
+
response.writeHead('200', responseHeader);
|
|
137
|
+
response.write(isXHR ? source : resolveImport(source, fileType !== "application/javascript"));
|
|
138
|
+
response.end();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// 对于大文件,使用流读取
|
|
142
|
+
else {
|
|
143
|
+
sendType = "Stream";
|
|
144
|
+
|
|
145
|
+
responseHeader['Content-Length'] = fileInfo.size
|
|
146
|
+
|
|
147
|
+
response.writeHead('200', responseHeader);
|
|
148
|
+
createReadStream(filePath).pipe(response);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
console.log("<i> \x1b[1m\x1b[32m[" + name + "] " + sendType + " File: " + url + '\x1b[0m ' + new Date().toLocaleString() + "\x1b[33m\x1b[1m" + (isXHR ? " 请求" : "") + "\x1b[0m");
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// 否则就是404
|
|
155
|
+
else {
|
|
156
|
+
response.writeHead(404, {
|
|
157
|
+
'Content-Type': "text/html;charset=utf-8",
|
|
158
|
+
'Access-Control-Allow-Origin': '*',
|
|
159
|
+
'Server': 'Powered by ' + name + '@' + version
|
|
160
|
+
});
|
|
161
|
+
response.write(resolve404(filePath, url));
|
|
162
|
+
response.end();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
Server.listen(port);
|
|
168
|
+
|
|
169
|
+
// 获取网络信息
|
|
170
|
+
let networkValue = network();
|
|
171
|
+
|
|
172
|
+
// 打印成功提示
|
|
173
|
+
console.log('<i> \x1b[1m\x1b[32m[' + name + '] Project is running at:\x1b[0m');
|
|
174
|
+
console.log('<i> \x1b[1m\x1b[32m[' + name + '] Loopback: \x1b[36mhttp://localhost:' + port + '/\x1b[0m');
|
|
175
|
+
for (let ipv4Item of networkValue.IPv4) console.log('<i> \x1b[1m\x1b[32m[' + name + '] On Your Network (IPv4):\x1b[36m http://' + ipv4Item.address + ':' + port + '/\x1b[0m');
|
|
176
|
+
for (let ipv6Item of networkValue.IPv6) console.log('<i> \x1b[1m\x1b[32m[' + name + '] On Your Network (IPv6): \x1b[36mhttp://[' + ipv6Item.address + ']:' + port + '/\x1b[0m');
|
|
177
|
+
console.log('<i> \x1b[1m\x1b[32m[' + name + '] Content not from ' + (config.name || "OIPage") + ' is served from \x1b[36m"' + basePath + '" \x1b[0mdirectory');
|
|
178
|
+
if (!cache) console.log('<i> \x1b[1m\x1b[32m[' + name + '] Cancel 304 Cache!\x1b[0m');
|
|
179
|
+
console.log('\n' + (config.name || "OIPage") + ' ' + version + ' compiled \x1b[1m\x1b[32msuccessfully\x1b[0m in ' + (new Date().valueOf() - startTime) + ' ms\n')
|
|
180
180
|
};
|