@webqit/webflo 0.20.4-next.4 → 0.20.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/package.json +15 -9
- package/src/build-pi/esbuild-plugin-livejs-transform.js +35 -0
- package/src/build-pi/index.js +5 -7
- package/src/init-pi/index.js +1 -1
- package/src/init-pi/templates/pwa/public/manifest.json +2 -2
- package/src/runtime-pi/WebfloRuntime.js +14 -23
- package/src/runtime-pi/apis.js +1 -1
- package/src/runtime-pi/webflo-client/DeviceCapabilities.js +1 -1
- package/src/runtime-pi/webflo-client/WebfloClient.js +2 -3
- package/src/runtime-pi/webflo-client/WebfloRootClient1.js +4 -8
- package/src/runtime-pi/webflo-client/WebfloRootClient2.js +1 -1
- package/src/runtime-pi/webflo-client/WebfloSubClient.js +1 -1
- package/src/runtime-pi/webflo-client/bootstrap.js +0 -1
- package/src/runtime-pi/webflo-fetch/LiveResponse.js +27 -34
- package/src/runtime-pi/webflo-fetch/index.js +14 -15
- package/src/runtime-pi/webflo-messaging/wq-message-port.js +1 -1
- package/src/runtime-pi/webflo-routing/HttpEvent.js +6 -8
- package/src/runtime-pi/webflo-routing/WebfloRouter.js +7 -12
- package/src/runtime-pi/webflo-server/WebfloServer.js +22 -57
- package/src/runtime-pi/webflo-server/webflo-devmode.js +7 -11
- package/src/runtime-pi/webflo-url/Url.js +1 -1
- package/src/runtime-pi/webflo-url/xURL.js +1 -1
- package/src/runtime-pi/webflo-worker/bootstrap.js +0 -1
- package/src/build-pi/esbuild-plugin-uselive-transform.js +0 -42
- package/src/init-pi/templates/pwa/.gitignore +0 -6
- package/src/init-pi/templates/pwa/.webqit/webflo/client.json +0 -15
- package/src/init-pi/templates/pwa/.webqit/webflo/layout.json +0 -7
- package/src/init-pi/templates/web/.gitignore +0 -6
- package/src/init-pi/templates/web/.webqit/webflo/client.json +0 -12
- package/src/init-pi/templates/web/.webqit/webflo/layout.json +0 -7
package/package.json
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
"vanila-javascript"
|
|
13
13
|
],
|
|
14
14
|
"homepage": "https://webqit.io/tooling/webflo",
|
|
15
|
-
"version": "0.20.4
|
|
15
|
+
"version": "0.20.4",
|
|
16
16
|
"license": "MIT",
|
|
17
17
|
"repository": {
|
|
18
18
|
"type": "git",
|
|
@@ -42,15 +42,25 @@
|
|
|
42
42
|
"webflo-certbot-http-cleanup-hook": "src/services-pi/cert/http-cleanup-hook.js"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
+
"@linked-db/linked-ql": "^0.30.13",
|
|
45
46
|
"@octokit/webhooks": "^7.15.1",
|
|
46
47
|
"@webqit/backpack": "^0.1.12",
|
|
47
|
-
"@webqit/oohtml-ssr": "^2.
|
|
48
|
-
"@webqit/
|
|
48
|
+
"@webqit/oohtml-ssr": "^2.1.1",
|
|
49
|
+
"@webqit/quantum-js": "^4.6.3",
|
|
49
50
|
"@webqit/util": "^0.8.11",
|
|
50
51
|
"dotenv": "^16.4.7",
|
|
52
|
+
"fs-extra": "^11.3.0",
|
|
53
|
+
"i": "^0.3.7",
|
|
54
|
+
"ioredis": "^5.5.0",
|
|
55
|
+
"jsdom": "^21.1.1",
|
|
56
|
+
"markdown-it-mathjax3": "^4.3.2",
|
|
51
57
|
"mime-types": "^2.1.33",
|
|
58
|
+
"npm": "^11.4.0",
|
|
59
|
+
"pg": "^8.13.3",
|
|
52
60
|
"simple-git": "^2.20.1",
|
|
53
|
-
"urlpattern-polyfill": "^4.0.3"
|
|
61
|
+
"urlpattern-polyfill": "^4.0.3",
|
|
62
|
+
"vitepress-plugin-mermaid": "^2.0.17",
|
|
63
|
+
"web-push": "^3.6.7"
|
|
54
64
|
},
|
|
55
65
|
"devDependencies": {
|
|
56
66
|
"chai": "^4.3.6",
|
|
@@ -58,13 +68,9 @@
|
|
|
58
68
|
"coveralls": "^3.1.1",
|
|
59
69
|
"esbuild": "^0.14.38",
|
|
60
70
|
"fast-glob": "^3.3.3",
|
|
61
|
-
"jsdom": "^27.0.1",
|
|
62
|
-
"markdown-it-mathjax3": "^4.3.2",
|
|
63
71
|
"mocha": "^10.0.0",
|
|
64
72
|
"mocha-lcov-reporter": "^1.3.0",
|
|
65
|
-
"vitepress": "^1.6.4"
|
|
66
|
-
"vitepress-plugin-mermaid": "^2.0.17",
|
|
67
|
-
"web-push": "^3.6.7"
|
|
73
|
+
"vitepress": "^1.6.4"
|
|
68
74
|
},
|
|
69
75
|
"author": "Oxford Harrison <oxharris.dev@gmail.com>",
|
|
70
76
|
"maintainers": [
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import Fs from 'fs/promises';
|
|
2
|
+
//import { transformQuantum } from '@webqit/quantum-js';
|
|
3
|
+
|
|
4
|
+
export function LiveJSTransform() {
|
|
5
|
+
return {
|
|
6
|
+
name: 'livejs-transform',
|
|
7
|
+
setup(build) {
|
|
8
|
+
build.onLoad({ filter: /\.(js|mjs|ts|jsx|tsx)$/ }, async (args) => {
|
|
9
|
+
let code = await Fs.readFile(args.path, 'utf8');
|
|
10
|
+
|
|
11
|
+
//console.log('LiveJS -- transform:', args);
|
|
12
|
+
|
|
13
|
+
// super dirty detection
|
|
14
|
+
if (!/\bquantum\s+function\b/.test(code) &&
|
|
15
|
+
!/\basync\s+quantum\s+function\b/.test(code)) {
|
|
16
|
+
return { contents: code, loader: 'default' };
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
console.log('LiveJS transform:', args.path);
|
|
21
|
+
|
|
22
|
+
return { contents: code, loader: 'default' };
|
|
23
|
+
const result = await transformQuantum(code, {
|
|
24
|
+
filename: args.path,
|
|
25
|
+
sourceMaps: true
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
return {
|
|
29
|
+
contents: result.code,
|
|
30
|
+
loader: 'js' // or 'ts' if you want esbuild TS transform after
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
package/src/build-pi/index.js
CHANGED
|
@@ -10,7 +10,7 @@ import { jsFile } from '@webqit/backpack/src/dotfile/index.js';
|
|
|
10
10
|
import { bootstrap as serverBootstrap } from '../runtime-pi/webflo-server/bootstrap.js';
|
|
11
11
|
import { bootstrap as clientBootstrap } from '../runtime-pi/webflo-client/bootstrap.js';
|
|
12
12
|
import { bootstrap as workerBootstrap } from '../runtime-pi/webflo-worker/bootstrap.js';
|
|
13
|
-
import {
|
|
13
|
+
import { LiveJSTransform } from './esbuild-plugin-livejs-transform.js';
|
|
14
14
|
import { CLIContext } from '../CLIContext.js';
|
|
15
15
|
import '../runtime-pi/webflo-url/urlpattern.js';
|
|
16
16
|
|
|
@@ -145,14 +145,14 @@ async function bundleScript({ $context, $source, which, outfile, asModule = true
|
|
|
145
145
|
const bundlingConfig = {
|
|
146
146
|
entryPoints: [moduleFile],
|
|
147
147
|
outfile,
|
|
148
|
+
bundle: which === 'server' ? false : true,
|
|
149
|
+
minify: true,
|
|
148
150
|
format: asModule ? 'esm' : 'iife',
|
|
149
151
|
platform: which === 'server' ? 'node' : 'browser', // optional but good for clarity
|
|
150
|
-
bundle: which === 'server' ? false : true,
|
|
151
|
-
minify: which === 'server' ? false : true,
|
|
152
152
|
treeShaking: true, // Important optimization
|
|
153
153
|
banner: { js: '/** @webqit/webflo */', },
|
|
154
154
|
footer: { js: '', },
|
|
155
|
-
plugins: [
|
|
155
|
+
plugins: [ LiveJSTransform() ],
|
|
156
156
|
...(restParams.buildParams || {})
|
|
157
157
|
};
|
|
158
158
|
if (!asModule) {
|
|
@@ -290,10 +290,8 @@ async function generateClientScript({ $context, bootstrap, ...restParams }) {
|
|
|
290
290
|
|
|
291
291
|
const configExport = structuredClone({ ENV: bootstrap.config.ENV, CLIENT: bootstrap.config.CLIENT, WORKER: {} });
|
|
292
292
|
if (bootstrap.config.CLIENT.capabilities?.service_worker === true) {
|
|
293
|
-
const outfile_workerBuild = Path.join(FLAGS.outdir || bootstrap.outdir, bootstrap.config.WORKER.filename);
|
|
294
|
-
const outfile_workerBuildPublic = Path.join(publicBaseUrl, Path.relative(bootstrap.config.LAYOUT.PUBLIC_DIR, outfile_workerBuild));
|
|
295
293
|
configExport.WORKER = {
|
|
296
|
-
filename:
|
|
294
|
+
filename: Path.join(publicBaseUrl.replace(/^\//, ''), bootstrap.config.WORKER.filename),
|
|
297
295
|
scope: bootstrap.config.WORKER.scope
|
|
298
296
|
};
|
|
299
297
|
}
|
package/src/init-pi/index.js
CHANGED
|
@@ -40,7 +40,7 @@ export async function init(projectName = 'my-webflo-app', projectTitle = '', pro
|
|
|
40
40
|
process.exit(1);
|
|
41
41
|
}
|
|
42
42
|
|
|
43
|
-
LOGGER?.log(LOGGER.style.keyword(`> `) + `Initializing your webflo app "${projectName}" using template "${template}"...\n`);
|
|
43
|
+
LOGGER?.log(LOGGER.style.keyword(`> `) + `Initializing your webflo app: "${projectName}" using template "${template}"...\n`);
|
|
44
44
|
|
|
45
45
|
// 1. Create project dir
|
|
46
46
|
await Fs2.mkdir(targetDir, { recursive: true });
|
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
"scope": "/",
|
|
11
11
|
"icons": [
|
|
12
12
|
{
|
|
13
|
-
"src": "/assets
|
|
13
|
+
"src": "/assets/...",
|
|
14
14
|
"sizes": "192x192",
|
|
15
15
|
"type": "image/png"
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
|
-
"src": "/assets
|
|
18
|
+
"src": "/assets/...",
|
|
19
19
|
"sizes": "512x512",
|
|
20
20
|
"type": "image/png",
|
|
21
21
|
"purpose": "maskable"
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { WebfloRouter } from './webflo-routing/WebfloRouter.js';
|
|
2
|
-
import { response as responseShim, headers as headersShim } from './webflo-fetch/index.js';
|
|
3
|
-
import { LiveResponse } from './webflo-fetch/LiveResponse.js';
|
|
2
|
+
import { LiveResponse, response as responseShim, headers as headersShim } from './webflo-fetch/index.js';
|
|
4
3
|
import { AppBootstrap } from './AppBootstrap.js';
|
|
5
4
|
import { _wq } from '../util.js';
|
|
6
5
|
|
|
@@ -32,14 +31,6 @@ export class WebfloRuntime {
|
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
async initialize() {
|
|
35
|
-
if (this.bootstrap.init.SETUP) {
|
|
36
|
-
await this.bootstrap.init.SETUP(this);
|
|
37
|
-
}
|
|
38
|
-
await this.initCreateStorage();
|
|
39
|
-
return this.#instanceController;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
async initCreateStorage() {
|
|
43
34
|
if (!this.bootstrap.init.createStorage) {
|
|
44
35
|
const inmemSessionRegistry = new Map;
|
|
45
36
|
this.bootstrap.init.createStorage = (namespace) => {
|
|
@@ -64,8 +55,8 @@ export class WebfloRuntime {
|
|
|
64
55
|
return this.#instanceController;
|
|
65
56
|
}
|
|
66
57
|
|
|
67
|
-
createStorage(namespace, ttl) {
|
|
68
|
-
|
|
58
|
+
async createStorage(namespace, ttl) {
|
|
59
|
+
return await this.bootstrap.init.createStorage(namespace, ttl);
|
|
69
60
|
}
|
|
70
61
|
|
|
71
62
|
createRequest(href, init = {}) {
|
|
@@ -99,7 +90,7 @@ export class WebfloRuntime {
|
|
|
99
90
|
}
|
|
100
91
|
// Dispatch event
|
|
101
92
|
const router = new this.constructor.Router(this, httpEvent.url.pathname);
|
|
102
|
-
await router.route(['SETUP'], httpEvent
|
|
93
|
+
await router.route(['SETUP'], httpEvent);
|
|
103
94
|
// Do proper routing for respone
|
|
104
95
|
const response = await new Promise(async (resolve) => {
|
|
105
96
|
let autoLiveResponse, response;
|
|
@@ -121,11 +112,10 @@ export class WebfloRuntime {
|
|
|
121
112
|
console.error(e);
|
|
122
113
|
response = new Response(null, { status: 500, statusText: e.message });
|
|
123
114
|
}
|
|
124
|
-
if (
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
: responseShim.from.value(response);
|
|
115
|
+
if (!(response instanceof LiveResponse) && !(response instanceof Response)) {
|
|
116
|
+
response = LiveResponse.test(response) === 'Default'
|
|
117
|
+
? responseShim.from.value(response)
|
|
118
|
+
: await LiveResponse.from(response, { responsesOK: true });
|
|
129
119
|
}
|
|
130
120
|
// Any "carry" data?
|
|
131
121
|
//await this.handleCarries(httpEvent, response);
|
|
@@ -136,14 +126,15 @@ export class WebfloRuntime {
|
|
|
136
126
|
resolve(response);
|
|
137
127
|
}
|
|
138
128
|
});
|
|
139
|
-
|
|
140
129
|
// Commit data in the exact order. Reason: in how they depend on each other
|
|
141
130
|
for (const storage of [httpEvent.user, httpEvent.session, httpEvent.cookies]) {
|
|
142
131
|
await storage?.commit?.(response, FLAGS['dev']);
|
|
143
132
|
}
|
|
144
|
-
|
|
145
|
-
if (LiveResponse.test(response) === 'LiveResponse' && response.whileLive()) {
|
|
133
|
+
if (response instanceof LiveResponse && response.whileLive()) {
|
|
146
134
|
httpEvent.waitUntil(response.whileLive(true));
|
|
135
|
+
} else {
|
|
136
|
+
httpEvent.waitUntil(Promise.resolve());
|
|
137
|
+
await null; // We need the above resolved before we move on
|
|
147
138
|
}
|
|
148
139
|
|
|
149
140
|
// Send the X-Background-Messaging-Port header
|
|
@@ -182,9 +173,9 @@ export class WebfloRuntime {
|
|
|
182
173
|
});
|
|
183
174
|
}
|
|
184
175
|
|
|
185
|
-
if (!this.isClientSide &&
|
|
176
|
+
if (!this.isClientSide && response instanceof LiveResponse) {
|
|
186
177
|
// Must convert to Response on the server-side before returning
|
|
187
|
-
return
|
|
178
|
+
return response.toResponse({ client: httpEvent.client });
|
|
188
179
|
}
|
|
189
180
|
|
|
190
181
|
return response;
|
package/src/runtime-pi/apis.js
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { _before, _toTitle } from '@webqit/util/str/index.js';
|
|
2
2
|
import { _isObject } from '@webqit/util/js/index.js';
|
|
3
|
-
import { Observer } from '@webqit/
|
|
3
|
+
import { Observer } from '@webqit/quantum-js';
|
|
4
4
|
import { WebfloRuntime } from '../WebfloRuntime.js';
|
|
5
5
|
import { WQMessageChannel } from '../webflo-messaging/WQMessageChannel.js';
|
|
6
|
-
import { response as responseShim } from '../webflo-fetch/index.js';
|
|
7
|
-
import { LiveResponse } from '../webflo-fetch/LiveResponse.js';
|
|
6
|
+
import { LiveResponse, response as responseShim } from '../webflo-fetch/index.js';
|
|
8
7
|
import { WQStarPort } from '../webflo-messaging/WQStarPort.js';
|
|
9
8
|
import { ClientSideCookies } from './ClientSideCookies.js';
|
|
10
9
|
import { HttpSession } from '../webflo-routing/HttpSession.js';
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { Observer } from '@webqit/
|
|
1
|
+
import { Observer } from '@webqit/quantum-js';
|
|
2
2
|
import { WebfloClient } from './WebfloClient.js';
|
|
3
3
|
import { ClientSideWorkport } from './ClientSideWorkport.js';
|
|
4
4
|
import { DeviceCapabilities } from './DeviceCapabilities.js';
|
|
5
|
-
import { response as responseShim } from '../webflo-fetch/index.js';
|
|
6
|
-
import { LiveResponse } from '../webflo-fetch/LiveResponse.js';
|
|
5
|
+
import { LiveResponse, response as responseShim } from '../webflo-fetch/index.js';
|
|
7
6
|
import { WebfloHMR } from './webflo-devmode.js';
|
|
8
7
|
|
|
9
8
|
export class WebfloRootClient1 extends WebfloClient {
|
|
@@ -93,10 +92,8 @@ export class WebfloRootClient1 extends WebfloClient {
|
|
|
93
92
|
cleanups.push(() => this.#capabilities.close());
|
|
94
93
|
if (this.config.CLIENT.capabilities?.service_worker) {
|
|
95
94
|
const { filename, ...restServiceWorkerParams } = this.config.WORKER;
|
|
96
|
-
this.constructor.Workport.initialize(null, filename, restServiceWorkerParams)
|
|
97
|
-
|
|
98
|
-
cleanups.push(() => this.#workport.close());
|
|
99
|
-
});
|
|
95
|
+
this.#workport = await this.constructor.Workport.initialize(null, (this.config.CLIENT.public_base_url || '') + filename, restServiceWorkerParams);
|
|
96
|
+
cleanups.push(() => this.#workport.close());
|
|
100
97
|
}
|
|
101
98
|
return instanceController;
|
|
102
99
|
}
|
|
@@ -116,7 +113,6 @@ export class WebfloRootClient1 extends WebfloClient {
|
|
|
116
113
|
this.background.addPort(backgroundPort);
|
|
117
114
|
}
|
|
118
115
|
if (scopeObj.response.body || backgroundPort) {
|
|
119
|
-
|
|
120
116
|
const httpEvent = this.createHttpEvent({ request: this.createRequest(this.location.href) }, true);
|
|
121
117
|
await this.render(httpEvent, scopeObj.response);
|
|
122
118
|
} else {
|
|
@@ -21,7 +21,6 @@ export async function bootstrap(cx, offset = '') {
|
|
|
21
21
|
};
|
|
22
22
|
if (config.CLIENT.copy_public_variables) {
|
|
23
23
|
const publicEnvPattern = /(?:^|_)PUBLIC(?:_|$)/;
|
|
24
|
-
config.ENV.data = config.ENV.data || {};
|
|
25
24
|
for (const key in process.env) {
|
|
26
25
|
if (publicEnvPattern.test(key)) {
|
|
27
26
|
config.ENV.data[key] = process.env[key];
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { State, Observer } from '@webqit/quantum-js';
|
|
2
2
|
import { _isObject, _isTypeObject } from '@webqit/util/js/index.js';
|
|
3
3
|
import { publishMutations, applyMutations } from '../webflo-messaging/wq-message-port.js';
|
|
4
4
|
import { WQBroadcastChannel } from '../webflo-messaging/WQBroadcastChannel.js';
|
|
@@ -9,11 +9,8 @@ import { isTypeStream } from './util.js';
|
|
|
9
9
|
|
|
10
10
|
export class LiveResponse extends EventTarget {
|
|
11
11
|
|
|
12
|
-
[Symbol.toStringTag] = 'LiveResponse';
|
|
13
|
-
|
|
14
12
|
static test(data) {
|
|
15
|
-
if (data instanceof LiveResponse
|
|
16
|
-
|| data?.[Symbol.toStringTag] === 'LiveResponse') {
|
|
13
|
+
if (data instanceof LiveResponse) {
|
|
17
14
|
return 'LiveResponse';
|
|
18
15
|
}
|
|
19
16
|
if (data instanceof Response) {
|
|
@@ -22,25 +19,24 @@ export class LiveResponse extends EventTarget {
|
|
|
22
19
|
if (isGenerator(data)) {
|
|
23
20
|
return 'Generator';
|
|
24
21
|
}
|
|
25
|
-
if (data instanceof
|
|
26
|
-
|
|
27
|
-
return 'LiveMode';
|
|
22
|
+
if (data instanceof State) {
|
|
23
|
+
return 'Quantum';
|
|
28
24
|
}
|
|
29
25
|
return 'Default';
|
|
30
26
|
}
|
|
31
27
|
|
|
32
28
|
static async from(data, ...args) {
|
|
33
|
-
if (
|
|
29
|
+
if (data instanceof LiveResponse) {
|
|
34
30
|
return data.clone(...args);
|
|
35
31
|
}
|
|
36
|
-
if (
|
|
32
|
+
if (data instanceof Response) {
|
|
37
33
|
return await this.fromResponse(data, ...args);
|
|
38
34
|
}
|
|
39
|
-
if (
|
|
35
|
+
if (isGenerator(data)) {
|
|
40
36
|
return await this.fromGenerator(data, ...args);
|
|
41
37
|
}
|
|
42
|
-
if (
|
|
43
|
-
return this.
|
|
38
|
+
if (data instanceof State) {
|
|
39
|
+
return this.fromQuantum(data, ...args);
|
|
44
40
|
}
|
|
45
41
|
return new this(data, ...args);
|
|
46
42
|
}
|
|
@@ -49,7 +45,7 @@ export class LiveResponse extends EventTarget {
|
|
|
49
45
|
if (!(response instanceof Response)) {
|
|
50
46
|
throw new Error('Argument must be a Response instance.');
|
|
51
47
|
}
|
|
52
|
-
|
|
48
|
+
|
|
53
49
|
const body = await responseShim.prototype.parse.value.call(response);
|
|
54
50
|
|
|
55
51
|
// Instance
|
|
@@ -112,7 +108,7 @@ export class LiveResponse extends EventTarget {
|
|
|
112
108
|
let $$await;
|
|
113
109
|
|
|
114
110
|
const $options = { done: firstFrame.done, ...options };
|
|
115
|
-
if (
|
|
111
|
+
if (value instanceof LiveResponse) {
|
|
116
112
|
instance = new this;
|
|
117
113
|
const responseMeta = _wq(value, 'meta');
|
|
118
114
|
_wq(instance).set('meta', responseMeta);
|
|
@@ -137,18 +133,15 @@ export class LiveResponse extends EventTarget {
|
|
|
137
133
|
return instance;
|
|
138
134
|
}
|
|
139
135
|
|
|
140
|
-
static async
|
|
141
|
-
if (!
|
|
142
|
-
throw new Error('Argument must be a
|
|
143
|
-
}
|
|
144
|
-
const instance = new this;
|
|
145
|
-
await instance.replaceWith(liveMode.value, { done: false, ...options });
|
|
146
|
-
if (instance.#generatorType === 'Default') {
|
|
147
|
-
instance.#generator = liveMode;
|
|
148
|
-
instance.#generatorType = 'LiveMode';
|
|
136
|
+
static async fromQuantum(qState, options = {}) {
|
|
137
|
+
if (!(qState instanceof State)) {
|
|
138
|
+
throw new Error('Argument must be a Quantum State instance.');
|
|
149
139
|
}
|
|
140
|
+
const instance = new this(qState.value, { done: false, ...options });
|
|
141
|
+
instance.#generator = qState;
|
|
142
|
+
instance.#generatorType = 'Quantum';
|
|
150
143
|
Observer.observe(
|
|
151
|
-
|
|
144
|
+
qState,
|
|
152
145
|
'value',
|
|
153
146
|
(e) => instance.#replaceWith(e.value),
|
|
154
147
|
{ signal: instance.#abortController.signal }
|
|
@@ -163,7 +156,8 @@ export class LiveResponse extends EventTarget {
|
|
|
163
156
|
}
|
|
164
157
|
|
|
165
158
|
static getBackground(respone) {
|
|
166
|
-
if (
|
|
159
|
+
if (!(respone instanceof Response)
|
|
160
|
+
&& !(respone instanceof LiveResponse)) return;
|
|
167
161
|
const responseMeta = _wq(respone, 'meta');
|
|
168
162
|
if (!responseMeta.has('background_port')) {
|
|
169
163
|
const value = respone.headers.get('X-Background-Messaging-Port')?.trim();
|
|
@@ -328,9 +322,8 @@ export class LiveResponse extends EventTarget {
|
|
|
328
322
|
const execReplaceWithResponse = async (response, options) => {
|
|
329
323
|
this.#generator = response;
|
|
330
324
|
this.#generatorType = response instanceof Response ? 'Response' : 'LiveResponse';
|
|
331
|
-
const body = response instanceof Response ? await responseShim.prototype.parse.value.call(response) : response.body;
|
|
332
325
|
execReplaceWith({
|
|
333
|
-
body,
|
|
326
|
+
body: response instanceof Response ? await responseShim.prototype.parse.value.call(response) : response.body,
|
|
334
327
|
status: responseShim.prototype.status.get.call(response),
|
|
335
328
|
statusText: response.statusText,
|
|
336
329
|
headers: response.headers,
|
|
@@ -339,7 +332,7 @@ export class LiveResponse extends EventTarget {
|
|
|
339
332
|
redirected: response.redirected,
|
|
340
333
|
url: response.url,
|
|
341
334
|
});
|
|
342
|
-
if (
|
|
335
|
+
if (response instanceof LiveResponse) {
|
|
343
336
|
response.addEventListener('replace', () => execReplaceWith(response), { signal: this.#abortController.signal });
|
|
344
337
|
return await response.whileLive(true);
|
|
345
338
|
}
|
|
@@ -367,7 +360,7 @@ export class LiveResponse extends EventTarget {
|
|
|
367
360
|
};
|
|
368
361
|
|
|
369
362
|
let donePromise;
|
|
370
|
-
if (
|
|
363
|
+
if (body instanceof Response || body instanceof LiveResponse) {
|
|
371
364
|
if (frameClosure) {
|
|
372
365
|
throw new Error('frameClosure unsupported for inputs of type response.');
|
|
373
366
|
}
|
|
@@ -446,8 +439,8 @@ export class LiveResponse extends EventTarget {
|
|
|
446
439
|
}));
|
|
447
440
|
}
|
|
448
441
|
|
|
449
|
-
|
|
450
|
-
const state = new
|
|
442
|
+
toQuantum({ signal: abortSignal } = {}) {
|
|
443
|
+
const state = new StateX;
|
|
451
444
|
const replaceHandler = () => Observer.defineProperty(state, 'value', { value: this.body, enumerable: true, configurable: true });
|
|
452
445
|
this.addEventListener('replace', replaceHandler, { signal: abortSignal });
|
|
453
446
|
replaceHandler();
|
|
@@ -469,7 +462,7 @@ export const isGenerator = (obj) => {
|
|
|
469
462
|
typeof obj?.return === 'function';
|
|
470
463
|
};
|
|
471
464
|
|
|
472
|
-
class
|
|
465
|
+
class StateX extends State {
|
|
473
466
|
constructor() { }
|
|
474
|
-
|
|
467
|
+
dispose() { }
|
|
475
468
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
+
export { LiveResponse } from './LiveResponse.js';
|
|
1
2
|
import { _isObject, _isTypeObject, _isNumeric } from '@webqit/util/js/index.js';
|
|
2
3
|
import { _from as _arrFrom } from '@webqit/util/arr/index.js';
|
|
3
4
|
import { _before, _after } from '@webqit/util/str/index.js';
|
|
4
5
|
import { DeepURLSearchParams } from '../webflo-url/util.js';
|
|
5
6
|
import { dataType } from './util.js';
|
|
6
7
|
import { _wq } from '../../util.js';
|
|
7
|
-
import { Observer } from '@webqit/use-live';
|
|
8
|
-
import { LiveResponse } from './LiveResponse.js';
|
|
9
8
|
|
|
10
9
|
// ----- env & globalize
|
|
11
10
|
|
|
@@ -31,8 +30,6 @@ export function shim(prefix = 'wq') {
|
|
|
31
30
|
patch(api.prototype, prototype);
|
|
32
31
|
}
|
|
33
32
|
}
|
|
34
|
-
globalThis.LiveResponse = LiveResponse;
|
|
35
|
-
globalThis.Observer = Observer;
|
|
36
33
|
}
|
|
37
34
|
|
|
38
35
|
// ----- request
|
|
@@ -339,23 +336,23 @@ export function renderHttpMessageInit(httpMessageInit) {
|
|
|
339
336
|
return { ..._headers, [name.toLowerCase()]: httpMessageInit.headers[name] };
|
|
340
337
|
}, {});
|
|
341
338
|
// Process body
|
|
342
|
-
let body = httpMessageInit.body,
|
|
343
|
-
type = dataType(httpMessageInit.body);
|
|
344
|
-
|
|
339
|
+
let body = httpMessageInit.body, type = dataType(httpMessageInit.body);
|
|
345
340
|
if (['Blob', 'File'].includes(type)) {
|
|
346
341
|
!headers['content-type'] && (headers['content-type'] = body.type);
|
|
347
342
|
!headers['content-length'] && (headers['content-length'] = body.size);
|
|
348
343
|
} else if (['Uint8Array', 'Uint16Array', 'Uint32Array', 'ArrayBuffer'].includes(type)) {
|
|
349
344
|
!headers['content-length'] && (headers['content-length'] = body.byteLength);
|
|
350
345
|
} else if (type === 'json' && _isTypeObject(body)/*JSON object*/) {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
346
|
+
if (!headers['content-type']) {
|
|
347
|
+
const [_body, isJsonfiable] = createFormDataFromJson(body, true/*jsonfy*/, true/*getIsJsonfiable*/);
|
|
348
|
+
if (isJsonfiable) {
|
|
349
|
+
body = JSON.stringify(body, (k, v) => v instanceof Error ? { ...v, message: v.message } : v);
|
|
350
|
+
headers['content-type'] = 'application/json';
|
|
351
|
+
headers['content-length'] = (new Blob([body])).size;
|
|
352
|
+
} else {
|
|
353
|
+
body = _body;
|
|
354
|
+
type = 'FormData';
|
|
355
|
+
}
|
|
359
356
|
}
|
|
360
357
|
} else if (type === 'json'/*JSON string*/ && !headers['content-length']) {
|
|
361
358
|
(headers['content-length'] = (body + '').length);
|
|
@@ -432,5 +429,7 @@ export function renderCookieObjToString(cookieObj) {
|
|
|
432
429
|
|
|
433
430
|
const importUrl = new URL(import.meta.url);
|
|
434
431
|
if (importUrl.searchParams.has('shim')) {
|
|
432
|
+
globalThis.LiveResponse = LiveResponse;
|
|
435
433
|
shim(importUrl.searchParams.get('shim')?.trim());
|
|
434
|
+
console.log('Webflo Fetch APIs shimmed.');
|
|
436
435
|
}
|
|
@@ -2,7 +2,7 @@ import { _isObject, _isTypeObject } from '@webqit/util/js/index.js';
|
|
|
2
2
|
import { WQMessagePort, WQMessagePortInstanceTag } from './WQMessagePort.js';
|
|
3
3
|
import { isTypeStream } from '../webflo-fetch/util.js';
|
|
4
4
|
import { WQMessageEvent } from './WQMessageEvent.js';
|
|
5
|
-
import { Observer } from '@webqit/
|
|
5
|
+
import { Observer } from '@webqit/quantum-js';
|
|
6
6
|
import { _wq } from '../../util.js';
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { _isObject } from '@webqit/util/js/index.js';
|
|
2
2
|
import { _difference } from '@webqit/util/arr/index.js';
|
|
3
|
-
import { LiveResponse } from '../webflo-fetch/
|
|
3
|
+
import { LiveResponse } from '../webflo-fetch/index.js';
|
|
4
4
|
import { xURL } from '../webflo-url/xURL.js';
|
|
5
5
|
import { _wq } from '../../util.js';
|
|
6
6
|
|
|
@@ -45,8 +45,6 @@ export class HttpEvent {
|
|
|
45
45
|
get state() { return { ...(this.#init.state || {}) }; }
|
|
46
46
|
|
|
47
47
|
#lifecyclePromises = new Set;
|
|
48
|
-
get lifecyclePromises() { return this.#lifecyclePromises; }
|
|
49
|
-
|
|
50
48
|
#lifeCycleResolve;
|
|
51
49
|
#lifeCycleReject;
|
|
52
50
|
#lifeCycleResolutionPromise = new Promise((resolve, reject) => {
|
|
@@ -82,12 +80,12 @@ export class HttpEvent {
|
|
|
82
80
|
&& !this.#lifecyclePromises.size;
|
|
83
81
|
}
|
|
84
82
|
|
|
85
|
-
|
|
86
|
-
return
|
|
83
|
+
waitUntil(promise) {
|
|
84
|
+
return this.#extendLifecycle(promise);
|
|
87
85
|
}
|
|
88
86
|
|
|
89
87
|
waitUntilNavigate() {
|
|
90
|
-
this.waitUntil(new Promise(() => { }));
|
|
88
|
+
return this.waitUntil(new Promise(() => { }));
|
|
91
89
|
}
|
|
92
90
|
|
|
93
91
|
#internalLiveResponse = new LiveResponse(null, { done: false });
|
|
@@ -102,8 +100,8 @@ export class HttpEvent {
|
|
|
102
100
|
}
|
|
103
101
|
|
|
104
102
|
extend(init = {}) {
|
|
105
|
-
const instance = this.constructor.create(this/*Main difference from clone*/, { ...this.#init, ...
|
|
106
|
-
|
|
103
|
+
const instance = this.constructor.create(this/*Main difference from clone*/, { ...this.#init, ...init });
|
|
104
|
+
this.#extendLifecycle(instance.lifeCycleComplete(true));
|
|
107
105
|
return instance;
|
|
108
106
|
}
|
|
109
107
|
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import { State } from '@webqit/quantum-js';
|
|
1
2
|
import { _isFunction, _isArray, _isObject } from '@webqit/util/js/index.js';
|
|
2
3
|
import { _from as _arrFrom } from '@webqit/util/arr/index.js';
|
|
3
|
-
import { LiveResponse } from '../webflo-fetch/LiveResponse.js';
|
|
4
4
|
import { path as Path } from '../webflo-url/util.js';
|
|
5
|
+
import { isGenerator } from '../webflo-fetch/LiveResponse.js';
|
|
5
6
|
|
|
6
7
|
export class WebfloRouter {
|
|
7
8
|
|
|
@@ -169,11 +170,11 @@ export class WebfloRouter {
|
|
|
169
170
|
const returnValue = await handler.call(thisContext, thisTick.event, $next/*next*/, $fetch/*fetch*/);
|
|
170
171
|
|
|
171
172
|
// Handle cleanup on abort
|
|
172
|
-
if (
|
|
173
|
+
if (returnValue instanceof State) {
|
|
173
174
|
thisTick.event.signal.addEventListener('abort', () => {
|
|
174
|
-
returnValue.
|
|
175
|
+
returnValue.dispose();
|
|
175
176
|
});
|
|
176
|
-
} else if (
|
|
177
|
+
} else if (isGenerator(returnValue)) {
|
|
177
178
|
thisTick.event.signal.addEventListener('abort', () => {
|
|
178
179
|
if (typeof returnValue.return === 'function') {
|
|
179
180
|
returnValue.return();
|
|
@@ -186,19 +187,13 @@ export class WebfloRouter {
|
|
|
186
187
|
resolved = 2;
|
|
187
188
|
resolve(returnValue);
|
|
188
189
|
} else if (typeof returnValue !== 'undefined') {
|
|
189
|
-
thisTick.event.internalLiveResponse.replaceWith(returnValue, { done: true });
|
|
190
|
+
await thisTick.event.internalLiveResponse.replaceWith(returnValue, { done: true });
|
|
190
191
|
}
|
|
191
192
|
});
|
|
192
193
|
}
|
|
193
|
-
let returnValue;
|
|
194
194
|
if (_default) {
|
|
195
|
-
|
|
195
|
+
return await _default.call(thisContext, thisTick.event, remoteFetch);
|
|
196
196
|
}
|
|
197
|
-
try {
|
|
198
|
-
// IMPORTANT: Explicitly terminate the event lifecycle if nothing extends it
|
|
199
|
-
await thisTick.event.waitUntil();
|
|
200
|
-
} catch(e) {}
|
|
201
|
-
return returnValue;
|
|
202
197
|
};
|
|
203
198
|
|
|
204
199
|
return next({
|
|
@@ -23,7 +23,7 @@ import { ServerSideSession } from './ServerSideSession.js';
|
|
|
23
23
|
import { HttpEvent } from '../webflo-routing/HttpEvent.js';
|
|
24
24
|
import { HttpUser } from '../webflo-routing/HttpUser.js';
|
|
25
25
|
import { response as responseShim, headers as headersShim } from '../webflo-fetch/index.js';
|
|
26
|
-
import {
|
|
26
|
+
import { LiveJSTransform } from '../../build-pi/esbuild-plugin-livejs-transform.js';
|
|
27
27
|
import { createWindow } from '@webqit/oohtml-ssr';
|
|
28
28
|
import { _wq } from '../../util.js';
|
|
29
29
|
import '../webflo-fetch/index.js';
|
|
@@ -57,6 +57,7 @@ export class WebfloServer extends WebfloRuntime {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
async initialize() {
|
|
60
|
+
const instanceController = await super.initialize();
|
|
60
61
|
const { appMeta: APP_META, flags: FLAGS, logger: LOGGER, } = this.cx;
|
|
61
62
|
|
|
62
63
|
// ----------
|
|
@@ -64,18 +65,9 @@ export class WebfloServer extends WebfloRuntime {
|
|
|
64
65
|
if (FLAGS['dev']) {
|
|
65
66
|
await this.enterDevMode();
|
|
66
67
|
} else {
|
|
67
|
-
await this.buildRoutes(
|
|
68
|
-
await this.bundleAssetsIfPending(true);
|
|
68
|
+
await this.buildRoutes();
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
// ----------
|
|
72
|
-
// Call default-init
|
|
73
|
-
const instanceController = await super.initialize();
|
|
74
|
-
|
|
75
|
-
// ----------
|
|
76
|
-
// Start serving
|
|
77
|
-
this.control();
|
|
78
|
-
|
|
79
71
|
// ----------
|
|
80
72
|
// Show proxies
|
|
81
73
|
const { PROXY } = this.config;
|
|
@@ -98,6 +90,10 @@ export class WebfloServer extends WebfloRuntime {
|
|
|
98
90
|
}
|
|
99
91
|
}
|
|
100
92
|
|
|
93
|
+
// ----------
|
|
94
|
+
// Start serving
|
|
95
|
+
this.control();
|
|
96
|
+
|
|
101
97
|
// ----------
|
|
102
98
|
// Show server details
|
|
103
99
|
if (this.#servers.size) {
|
|
@@ -112,22 +108,22 @@ export class WebfloServer extends WebfloRuntime {
|
|
|
112
108
|
return instanceController;
|
|
113
109
|
}
|
|
114
110
|
|
|
115
|
-
async buildRoutes({ client = false, worker = false,
|
|
111
|
+
async buildRoutes({ client = false, worker = false, ...options } = {}) {
|
|
116
112
|
const routeDirs = [...new Set([this.config.LAYOUT.CLIENT_DIR, this.config.LAYOUT.WORKER_DIR, this.config.LAYOUT.SERVER_DIR])];
|
|
117
|
-
const entryPoints = await $glob(routeDirs.map((d) => `${d}/**/handler{${client ? ',.client' : ''}${worker ? ',.worker' : ''}
|
|
113
|
+
const entryPoints = await $glob(routeDirs.map((d) => `${d}/**/handler{${client ? ',.client' : ''}${worker ? ',.worker' : ''},.server}.js`), { absolute: true })
|
|
118
114
|
.then((files) => files.map((file) => file.replace(/\\/g, '/')));
|
|
119
|
-
const
|
|
115
|
+
const entryNames = routeDirs.length === 1 ? `${Path.relative(process.cwd(), routeDirs[0])}/[dir]/[name]` : `[dir]/[name]`;
|
|
120
116
|
const bundlingConfig = {
|
|
121
|
-
entryPoints
|
|
117
|
+
entryPoints,
|
|
122
118
|
outdir: this.config.RUNTIME_DIR,
|
|
123
|
-
|
|
119
|
+
entryNames,
|
|
120
|
+
bundle: true,
|
|
124
121
|
format: 'esm',
|
|
125
|
-
|
|
126
|
-
bundle: server ? false : true,
|
|
127
|
-
minify: server ? false : true,
|
|
122
|
+
minify: false,
|
|
128
123
|
sourcemap: false,
|
|
129
|
-
|
|
130
|
-
|
|
124
|
+
platform: 'browser', // optional but good for clarity
|
|
125
|
+
treeShaking: true, // Important optimization
|
|
126
|
+
plugins: [ LiveJSTransform() ],
|
|
131
127
|
...options,
|
|
132
128
|
};
|
|
133
129
|
return await EsBuild.build(bundlingConfig);
|
|
@@ -145,7 +141,6 @@ export class WebfloServer extends WebfloRuntime {
|
|
|
145
141
|
buildSensitivity: parseInt(FLAGS['build-sensitivity'] || 0),
|
|
146
142
|
});
|
|
147
143
|
await this.#hmr.buildRoutes(true);
|
|
148
|
-
await this.#hmr.bundleAssetsIfPending(true);
|
|
149
144
|
if (FLAGS['open']) {
|
|
150
145
|
for (let [proto, def] of this.#servers) {
|
|
151
146
|
const url = `${proto}://${def.hostnames.find((h) => h !== '*') || 'localhost'}:${def.port}`;
|
|
@@ -154,35 +149,6 @@ export class WebfloServer extends WebfloRuntime {
|
|
|
154
149
|
}
|
|
155
150
|
}
|
|
156
151
|
|
|
157
|
-
async initCreateStorage() {
|
|
158
|
-
if (this.bootstrap.init.createStorage
|
|
159
|
-
|| !this.bootstrap.init.redis) {
|
|
160
|
-
return super.initCreateStorage();
|
|
161
|
-
}
|
|
162
|
-
const redis = this.bootstrap.init.redis;
|
|
163
|
-
this.bootstrap.init.createStorage = (namespace, ttl = null) => ({
|
|
164
|
-
async has(key) { return await redis.hexists(namespace, key); },
|
|
165
|
-
async get(key) {
|
|
166
|
-
const value = await redis.hget(namespace, key);
|
|
167
|
-
return typeof value === 'undefined' ? value : JSON.parse(value);
|
|
168
|
-
},
|
|
169
|
-
async set(key, value) {
|
|
170
|
-
const returnValue = await redis.hset(namespace, key, JSON.stringify(value));
|
|
171
|
-
if (!this.ttlApplied && ttl) {
|
|
172
|
-
await redis.expire(namespace, ttl);
|
|
173
|
-
this.ttlApplied = true;
|
|
174
|
-
}
|
|
175
|
-
return returnValue;
|
|
176
|
-
},
|
|
177
|
-
async delete(key) { return await redis.hdel(namespace, key); },
|
|
178
|
-
async clear() { return await redis.del(namespace); },
|
|
179
|
-
async keys() { return await redis.hkeys(namespace); },
|
|
180
|
-
async values() { return (await redis.hvals(namespace) || []).map((value) => typeof value === 'undefined' ? value : JSON.parse(value)); },
|
|
181
|
-
async entries() { return Object.entries(await redis.hgetall(namespace) || {}).map(([key, value]) => [key, typeof value === 'undefined' ? value : JSON.parse(value)]); },
|
|
182
|
-
get size() { return redis.hlen(namespace); },
|
|
183
|
-
});
|
|
184
|
-
}
|
|
185
|
-
|
|
186
152
|
control() {
|
|
187
153
|
const { flags: FLAGS } = this.cx;
|
|
188
154
|
const { SERVER, PROXY } = this.config;
|
|
@@ -562,10 +528,6 @@ export class WebfloServer extends WebfloRuntime {
|
|
|
562
528
|
}
|
|
563
529
|
scopeObj.ext = Path.parse(scopeObj.filename).ext;
|
|
564
530
|
const finalizeResponse = (response) => {
|
|
565
|
-
// Qualify Service-Worker responses
|
|
566
|
-
if (httpEvent.request.headers.get('Service-Worker') === 'script') {
|
|
567
|
-
scopeObj.response.headers.set('Service-Worker-Allowed', this.config.WORKER.scope || '/');
|
|
568
|
-
}
|
|
569
531
|
const responseMeta = _wq(response, 'meta');
|
|
570
532
|
responseMeta.set('filename', scopeObj.filename);
|
|
571
533
|
responseMeta.set('static', true);
|
|
@@ -635,7 +597,10 @@ export class WebfloServer extends WebfloRuntime {
|
|
|
635
597
|
scopeObj.response.headers.set('X-Frame-Options', 'SAMEORIGIN');
|
|
636
598
|
// 5. Partial content support
|
|
637
599
|
scopeObj.response.headers.set('Accept-Ranges', 'bytes');
|
|
638
|
-
|
|
600
|
+
// 6. Qualify Service-Worker responses
|
|
601
|
+
if (httpEvent.request.headers.get('Service-Worker') === 'script') {
|
|
602
|
+
scopeObj.response.headers.set('Service-Worker-Allowed', this.config.WORKER.scope || '/');
|
|
603
|
+
}
|
|
639
604
|
return finalizeResponse(scopeObj.response);
|
|
640
605
|
}
|
|
641
606
|
|
|
@@ -710,7 +675,7 @@ export class WebfloServer extends WebfloRuntime {
|
|
|
710
675
|
const asHTML = requestAccept?.match('text/html');
|
|
711
676
|
const asIs = requestAccept?.match(response.headers.get('Content-Type'));
|
|
712
677
|
const responseMeta = _wq(response, 'meta');
|
|
713
|
-
if (requestAccept && asHTML
|
|
678
|
+
if (requestAccept && asHTML >= asIs && !responseMeta.get('static')) {
|
|
714
679
|
response = await this.render(httpEvent, response);
|
|
715
680
|
} else if (requestAccept && response.headers.get('Content-Type') && !asIs) {
|
|
716
681
|
return new Response(response.body, { status: 406, statusText: 'Not Acceptable', headers: response.headers });
|
|
@@ -182,17 +182,13 @@ export class WebfloHMR {
|
|
|
182
182
|
const bundlingConfig = {
|
|
183
183
|
client: true,
|
|
184
184
|
worker: true,
|
|
185
|
-
server: true,
|
|
186
185
|
metafile: true, // This is key
|
|
187
186
|
logLevel: 'silent', // Suppress output
|
|
188
187
|
incremental: true,
|
|
189
188
|
};
|
|
190
189
|
buildResult = await this.#app.buildRoutes(bundlingConfig);
|
|
191
190
|
}
|
|
192
|
-
} catch (e) {
|
|
193
|
-
//console.error(e);
|
|
194
|
-
return false;
|
|
195
|
-
}
|
|
191
|
+
} catch (e) { return false; }
|
|
196
192
|
|
|
197
193
|
// 1. Forward dependency graph (file -> [imported files])
|
|
198
194
|
const forward = {};
|
|
@@ -232,25 +228,25 @@ export class WebfloHMR {
|
|
|
232
228
|
return true;
|
|
233
229
|
}
|
|
234
230
|
|
|
235
|
-
async bundleAssetsIfPending(
|
|
231
|
+
async bundleAssetsIfPending() {
|
|
236
232
|
const entries = {};
|
|
237
233
|
|
|
238
|
-
if (this.#dirtiness.clientRoutesAffected.size || this.#dirtiness.serviceWorkerAffected
|
|
234
|
+
if (this.#dirtiness.clientRoutesAffected.size || this.#dirtiness.serviceWorkerAffected) {
|
|
239
235
|
entries.js = {};
|
|
240
|
-
entries.js.client = !!this.#dirtiness.clientRoutesAffected.size
|
|
241
|
-
entries.js.worker = this.#dirtiness.serviceWorkerAffected
|
|
236
|
+
entries.js.client = !!this.#dirtiness.clientRoutesAffected.size;
|
|
237
|
+
entries.js.worker = this.#dirtiness.serviceWorkerAffected;
|
|
242
238
|
entries.js.server = false;
|
|
243
239
|
// Clear state
|
|
244
240
|
this.#dirtiness.clientRoutesAffected.clear();
|
|
245
241
|
this.#dirtiness.serviceWorkerAffected = false;
|
|
246
242
|
}
|
|
247
243
|
|
|
248
|
-
if (this.#dirtiness.HTMLAffected
|
|
244
|
+
if (this.#dirtiness.HTMLAffected) {
|
|
249
245
|
this.#dirtiness.HTMLAffected = false;
|
|
250
246
|
entries.html = {};
|
|
251
247
|
}
|
|
252
248
|
|
|
253
|
-
if (this.#dirtiness.CSSAffected
|
|
249
|
+
if (this.#dirtiness.CSSAffected) {
|
|
254
250
|
this.#dirtiness.CSSAffected = false;
|
|
255
251
|
entries.css = {};
|
|
256
252
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { _with } from '@webqit/util/obj/index.js';
|
|
2
2
|
import { _isArray, _isObject, _isTypeObject, _isString, _isEmpty } from '@webqit/util/js/index.js';
|
|
3
3
|
import { DeepURLSearchParams } from './util.js';
|
|
4
|
-
import { Observer } from '@webqit/
|
|
4
|
+
import { Observer } from '@webqit/quantum-js';
|
|
5
5
|
|
|
6
6
|
export class Url {
|
|
7
7
|
|
|
@@ -21,7 +21,6 @@ export async function bootstrap(cx, offset = '') {
|
|
|
21
21
|
};
|
|
22
22
|
if (config.CLIENT.copy_public_variables) {
|
|
23
23
|
const publicEnvPattern = /(?:^|_)PUBLIC(?:_|$)/;
|
|
24
|
-
config.ENV.data = config.ENV.data || {};
|
|
25
24
|
for (const key in process.env) {
|
|
26
25
|
if (publicEnvPattern.test(key)) {
|
|
27
26
|
config.ENV.data[key] = process.env[key];
|
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
import Fs from 'fs/promises';
|
|
2
|
-
import { parse, compile, matchPrologDirective, serialize } from '@webqit/use-live';
|
|
3
|
-
|
|
4
|
-
export function UseLiveTransform() {
|
|
5
|
-
return {
|
|
6
|
-
name: 'uselive-transform',
|
|
7
|
-
setup(build) {
|
|
8
|
-
build.onLoad({ filter: /\.(js|mjs|ts|jsx|tsx)$/ }, async (args) => {
|
|
9
|
-
const code = await Fs.readFile(args.path, 'utf8');
|
|
10
|
-
|
|
11
|
-
// Super dirty detection
|
|
12
|
-
if (matchPrologDirective(code)) {
|
|
13
|
-
// Actual check...
|
|
14
|
-
|
|
15
|
-
let ast;
|
|
16
|
-
try { ast = parse(code, parserParams); } catch (e) { console.error(args.path, '\nUseLive transform error:', e); }
|
|
17
|
-
|
|
18
|
-
if (ast?.isLiveProgram || ast?.hasLiveFunctions) {
|
|
19
|
-
const result = await compile(parserParams.sourceType+'-file', ast, {
|
|
20
|
-
liveMode: ast.isLiveProgram, // Regarding top-level
|
|
21
|
-
fileName: args.path,
|
|
22
|
-
});
|
|
23
|
-
return { contents: serialize(result), loader: 'js' };
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return { contents: code, loader: 'default' };
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
export const parserParams = {
|
|
34
|
-
ecmaVersion: 'latest',
|
|
35
|
-
sourceType: 'module',
|
|
36
|
-
executionMode: 'RegularProgram', // 'LiveProgram'
|
|
37
|
-
allowReturnOutsideFunction: true,
|
|
38
|
-
allowAwaitOutsideFunction: true,
|
|
39
|
-
allowSuperOutsideMethod: false,
|
|
40
|
-
preserveParens: false,
|
|
41
|
-
locations: true,
|
|
42
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"filename": "app.js",
|
|
3
|
-
"public_base_url": "/",
|
|
4
|
-
"copy_public_variables": true,
|
|
5
|
-
"spa_routing": true,
|
|
6
|
-
"capabilities": {
|
|
7
|
-
"service_worker": true,
|
|
8
|
-
"webpush": true,
|
|
9
|
-
"custom_install": true,
|
|
10
|
-
"exposed": [
|
|
11
|
-
"display-mode",
|
|
12
|
-
"notifications"
|
|
13
|
-
]
|
|
14
|
-
}
|
|
15
|
-
}
|