@lowdefy/server-dev 4.0.0-alpha.6 → 4.0.0-alpha.7
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/next.config.js +6 -4
- package/package.json +34 -32
- package/src/components/App.js +9 -7
- package/src/components/LowdefyContext.js +13 -13
- package/src/components/Page.js +2 -2
- package/src/components/Reload.js +2 -2
- package/src/components/block/CategorySwitch.js +2 -5
- package/src/components/block/Container.js +1 -2
- package/src/components/block/List.js +1 -2
- package/src/components/{components.js → createComponents.js} +8 -4
- package/src/components/createLinkComponent.js +97 -0
- package/src/manager/getContext.mjs +36 -21
- package/src/manager/{initialBuild.mjs → processes/initialBuild.mjs} +7 -4
- package/src/manager/processes/installPlugins.mjs +2 -2
- package/src/manager/processes/lowdefyBuild.mjs +4 -3
- package/src/manager/processes/nextBuild.mjs +4 -4
- package/src/manager/{watchers/configWatcher.mjs → processes/readDotEnv.mjs} +8 -8
- package/src/manager/processes/reloadClients.mjs +1 -1
- package/src/manager/processes/{startServerProcess.mjs → restartServer.mjs} +8 -15
- package/src/manager/processes/shutdownServer.mjs +35 -0
- package/src/manager/processes/startNextServer.mjs +45 -0
- package/src/manager/processes/startServer.mjs +3 -3
- package/src/manager/processes/startWatchers.mjs +31 -0
- package/src/manager/run.mjs +57 -6
- package/src/manager/{BatchChanges.mjs → utils/BatchChanges.mjs} +1 -0
- package/src/manager/utils/getLowdefyVersion.mjs +51 -0
- package/src/manager/{watchers → utils}/setupWatcher.mjs +12 -6
- package/src/manager/{spawnProcess.mjs → utils/spawnProcess.mjs} +0 -0
- package/src/manager/watchers/envWatcher.mjs +5 -3
- package/src/manager/watchers/lowdefyBuildWatcher.mjs +45 -0
- package/src/manager/watchers/nextBuildWatcher.mjs +93 -0
- package/src/pages/_app.js +4 -2
- package/src/pages/api/reload.js +0 -2
- package/src/pages/api/request/[pageId]/[requestId].js +1 -0
- package/src/utils/callRequest.js +2 -2
- package/src/utils/setPageId.js +3 -3
- package/src/utils/setupLink.js +22 -14
- package/src/utils/useMutateCache.js +3 -3
- package/src/utils/usePageConfig.js +2 -5
- package/src/utils/useRootConfig.js +4 -4
- package/src/utils/waitForRestartedServer.js +1 -1
- package/src/manager/watchers/startWatchers.mjs +0 -64
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2021 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
function shutdownServer(context) {
|
|
18
|
+
return () => {
|
|
19
|
+
if (context.nextServer) {
|
|
20
|
+
// console.log(
|
|
21
|
+
// `Existing server ${context.nextServer.pid}, killed: ${context.nextServer.killed}`
|
|
22
|
+
// );
|
|
23
|
+
if (!context.nextServer.killed) {
|
|
24
|
+
console.log('Shutting down server...');
|
|
25
|
+
context.nextServer.kill();
|
|
26
|
+
// console.log(
|
|
27
|
+
// `Killed server ${context.nextServer.pid}, killed: ${context.nextServer.killed}`
|
|
28
|
+
// );
|
|
29
|
+
}
|
|
30
|
+
context.nextServer = null;
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default shutdownServer;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2021 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import spawnProcess from '../utils/spawnProcess.mjs';
|
|
18
|
+
|
|
19
|
+
function startServerProcess(context) {
|
|
20
|
+
context.shutdownServer();
|
|
21
|
+
|
|
22
|
+
const nextServer = spawnProcess({
|
|
23
|
+
logger: console,
|
|
24
|
+
command: 'node',
|
|
25
|
+
args: [context.bin.next, 'start'],
|
|
26
|
+
silent: false,
|
|
27
|
+
processOptions: {
|
|
28
|
+
env: {
|
|
29
|
+
...process.env,
|
|
30
|
+
...context.serverEnv,
|
|
31
|
+
PORT: context.options.port,
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
});
|
|
35
|
+
// console.log(`Started server ${nextServer.pid}.`);
|
|
36
|
+
// nextServer.on('exit', (code, signal) => {
|
|
37
|
+
// console.log(`nextServer exit ${nextServer.pid}, signal: ${signal}, code: ${code}`);
|
|
38
|
+
// });
|
|
39
|
+
nextServer.on('error', (error) => {
|
|
40
|
+
console.log(error);
|
|
41
|
+
});
|
|
42
|
+
context.nextServer = nextServer;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default startServerProcess;
|
|
@@ -15,14 +15,14 @@
|
|
|
15
15
|
*/
|
|
16
16
|
/* eslint-disable no-console */
|
|
17
17
|
|
|
18
|
-
import
|
|
18
|
+
import startNextServer from './startNextServer.mjs';
|
|
19
19
|
|
|
20
20
|
async function startServer(context) {
|
|
21
21
|
return new Promise((resolve, reject) => {
|
|
22
|
-
context.serverProcessPromise = { resolve, reject };
|
|
23
22
|
try {
|
|
24
|
-
|
|
23
|
+
startNextServer(context);
|
|
25
24
|
} catch (error) {
|
|
25
|
+
console.log(error);
|
|
26
26
|
reject(error);
|
|
27
27
|
}
|
|
28
28
|
});
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2021 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import envWatcher from '../watchers/envWatcher.mjs';
|
|
18
|
+
import lowdefyBuildWatcher from '../watchers/lowdefyBuildWatcher.mjs';
|
|
19
|
+
import nextBuildWatcher from '../watchers/nextBuildWatcher.mjs';
|
|
20
|
+
|
|
21
|
+
function startWatchers(context) {
|
|
22
|
+
return async () => {
|
|
23
|
+
await Promise.all([
|
|
24
|
+
envWatcher(context),
|
|
25
|
+
lowdefyBuildWatcher(context),
|
|
26
|
+
nextBuildWatcher(context),
|
|
27
|
+
]);
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default startWatchers;
|
package/src/manager/run.mjs
CHANGED
|
@@ -18,21 +18,72 @@
|
|
|
18
18
|
import { wait } from '@lowdefy/helpers';
|
|
19
19
|
import opener from 'opener';
|
|
20
20
|
import getContext from './getContext.mjs';
|
|
21
|
-
import initialBuild from './initialBuild.mjs';
|
|
22
21
|
import startServer from './processes/startServer.mjs';
|
|
23
|
-
|
|
22
|
+
|
|
23
|
+
/*
|
|
24
|
+
The run script does the following:
|
|
25
|
+
- Run the initial Lowdefy build, install plugins, and next build and read .env
|
|
26
|
+
- Start file watchers to reload config and restart server if necessary
|
|
27
|
+
- Start the server
|
|
28
|
+
- Open a browser window.
|
|
29
|
+
|
|
30
|
+
Three watchers are started:
|
|
31
|
+
|
|
32
|
+
## Lowdefy build watcher
|
|
33
|
+
Watches:
|
|
34
|
+
- <config-dir>,
|
|
35
|
+
- <watch-dirs>
|
|
36
|
+
- !<ignore-dirs>
|
|
37
|
+
The Lowdefy build watcher watches the Lowdefy config files for changes
|
|
38
|
+
and runs Lowdefy build when they change, and triggers a soft reload.
|
|
39
|
+
|
|
40
|
+
If lowdefy version in lowdefy.yaml
|
|
41
|
+
is changed, the server warns and exits.
|
|
42
|
+
|
|
43
|
+
## .env watcher
|
|
44
|
+
|
|
45
|
+
If the .env file is changed, the new file is parsed, and the server restarted with the new env
|
|
46
|
+
and the server hard reloads.
|
|
47
|
+
|
|
48
|
+
## Next build watcher
|
|
49
|
+
|
|
50
|
+
The Next build watcher watches for any files where the app should be rebuilt and restarted.
|
|
51
|
+
It watches:
|
|
52
|
+
- <build-dir>/plugins/**
|
|
53
|
+
- <build-dir>/config.json
|
|
54
|
+
- <server-dir>/package.json
|
|
55
|
+
|
|
56
|
+
If app theme or config changes:
|
|
57
|
+
- <build-dir>/config.json changes, rebuild and restart server.
|
|
58
|
+
|
|
59
|
+
If new plugin type in an existing plugin package is used:
|
|
60
|
+
- <build-dir>/plugins/** changes, rebuild next and restart server.
|
|
61
|
+
|
|
62
|
+
If new plugin type in a new plugin package is used:
|
|
63
|
+
- <server-dir>/package.json changes, run npm install, rebuild next and restart server.
|
|
64
|
+
|
|
65
|
+
# Reload mechanism
|
|
66
|
+
|
|
67
|
+
The web client creates a Server Sent Events connection with the server on the /api/reload route.
|
|
68
|
+
The server watches the <build-dir>/reload file, which is written every time the server should reload,
|
|
69
|
+
and sends an event to the client to reload the config. The client then uses a SWR cache mutation to
|
|
70
|
+
fetch the new config.
|
|
71
|
+
|
|
72
|
+
If the server is restarted, the event stream is closed because the original server was shut down. The client starts
|
|
73
|
+
pinging the /api/ping route, until it detects a new server has started, and then reloads the window.
|
|
74
|
+
*/
|
|
24
75
|
|
|
25
76
|
async function run() {
|
|
26
77
|
const context = await getContext();
|
|
27
|
-
await initialBuild(
|
|
28
|
-
await startWatchers(
|
|
78
|
+
await context.initialBuild();
|
|
79
|
+
await context.startWatchers();
|
|
29
80
|
try {
|
|
30
81
|
const serverPromise = startServer(context);
|
|
31
82
|
await wait(800);
|
|
32
|
-
|
|
33
|
-
opener(`http://localhost:3000`);
|
|
83
|
+
opener(`http://localhost:${context.options.port}`);
|
|
34
84
|
await serverPromise;
|
|
35
85
|
} catch (error) {
|
|
86
|
+
console.log(error);
|
|
36
87
|
context.shutdownServer();
|
|
37
88
|
throw error;
|
|
38
89
|
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2021 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import path from 'path';
|
|
18
|
+
import { type } from '@lowdefy/helpers';
|
|
19
|
+
import { readFile } from '@lowdefy/node-utils';
|
|
20
|
+
import YAML from 'yaml';
|
|
21
|
+
|
|
22
|
+
async function getLowdefyVersion(context) {
|
|
23
|
+
let lowdefyYaml = await readFile(path.join(context.directories.config, 'lowdefy.yaml'));
|
|
24
|
+
if (!lowdefyYaml) {
|
|
25
|
+
lowdefyYaml = await readFile(path.join(context.directories.config, 'lowdefy.yml'));
|
|
26
|
+
}
|
|
27
|
+
if (!lowdefyYaml) {
|
|
28
|
+
throw new Error(`Could not find "lowdefy.yaml" file.`);
|
|
29
|
+
}
|
|
30
|
+
let lowdefy;
|
|
31
|
+
try {
|
|
32
|
+
lowdefy = YAML.parse(lowdefyYaml);
|
|
33
|
+
} catch (error) {
|
|
34
|
+
throw new Error(`Could not parse "lowdefy.yaml" file. Received error ${error.message}.`);
|
|
35
|
+
}
|
|
36
|
+
if (!lowdefy.lowdefy) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
`No version specified in "lowdefy.yaml" file. Specify a version in the "lowdefy" field.`
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
if (!type.isString(lowdefy.lowdefy)) {
|
|
42
|
+
throw new Error(
|
|
43
|
+
`Version number specified in "lowdefy.yaml" file should be a string. Received ${JSON.stringify(
|
|
44
|
+
lowdefy.lowdefy
|
|
45
|
+
)}.`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
return lowdefy.lowdefy;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default getLowdefyVersion;
|
|
@@ -15,14 +15,20 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import chokidar from 'chokidar';
|
|
18
|
-
import BatchChanges from '
|
|
18
|
+
import BatchChanges from './BatchChanges.mjs';
|
|
19
19
|
|
|
20
|
-
function setupWatcher({
|
|
20
|
+
function setupWatcher({
|
|
21
|
+
callback,
|
|
22
|
+
watchDotfiles = false,
|
|
23
|
+
ignorePaths = [],
|
|
24
|
+
watchPaths,
|
|
25
|
+
minDelay = 500,
|
|
26
|
+
}) {
|
|
21
27
|
return new Promise((resolve) => {
|
|
22
28
|
// const { watch = [], watchIgnore = [] } = context.options;
|
|
23
29
|
// const resolvedWatchPaths = watch.map((pathName) => path.resolve(pathName));
|
|
24
30
|
|
|
25
|
-
const batchChanges = new BatchChanges({ fn: callback });
|
|
31
|
+
const batchChanges = new BatchChanges({ fn: callback, minDelay });
|
|
26
32
|
const defaultIgnorePaths = watchDotfiles
|
|
27
33
|
? []
|
|
28
34
|
: [
|
|
@@ -33,9 +39,9 @@ function setupWatcher({ callback, watchDotfiles = false, ignorePaths = [], watch
|
|
|
33
39
|
persistent: true,
|
|
34
40
|
ignoreInitial: true,
|
|
35
41
|
});
|
|
36
|
-
configWatcher.on('add', (...args) => batchChanges.newChange(args));
|
|
37
|
-
configWatcher.on('change', (...args) => batchChanges.newChange(args));
|
|
38
|
-
configWatcher.on('unlink', (...args) => batchChanges.newChange(args));
|
|
42
|
+
configWatcher.on('add', (...args) => batchChanges.newChange(...args));
|
|
43
|
+
configWatcher.on('change', (...args) => batchChanges.newChange(...args));
|
|
44
|
+
configWatcher.on('unlink', (...args) => batchChanges.newChange(...args));
|
|
39
45
|
configWatcher.on('ready', () => resolve());
|
|
40
46
|
});
|
|
41
47
|
}
|
|
File without changes
|
|
@@ -13,13 +13,15 @@
|
|
|
13
13
|
See the License for the specific language governing permissions and
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
/* eslint-disable no-console */
|
|
16
17
|
|
|
17
18
|
import path from 'path';
|
|
18
|
-
import setupWatcher from '
|
|
19
|
+
import setupWatcher from '../utils/setupWatcher.mjs';
|
|
19
20
|
|
|
20
|
-
|
|
21
|
+
function envWatcher(context) {
|
|
21
22
|
const callback = async () => {
|
|
22
|
-
console.
|
|
23
|
+
console.warn('.env file changed.');
|
|
24
|
+
await context.readDotEnv();
|
|
23
25
|
context.restartServer();
|
|
24
26
|
};
|
|
25
27
|
return setupWatcher({
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2021 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/* eslint-disable no-console */
|
|
17
|
+
|
|
18
|
+
import getLowdefyVersion from '../utils/getLowdefyVersion.mjs';
|
|
19
|
+
import setupWatcher from '../utils/setupWatcher.mjs';
|
|
20
|
+
|
|
21
|
+
function lowdefyBuildWatcher(context) {
|
|
22
|
+
const callback = async (filePaths) => {
|
|
23
|
+
const lowdefyYamlModified = filePaths
|
|
24
|
+
.flat()
|
|
25
|
+
.some((filePath) => filePath.includes('lowdefy.yaml') || filePath.includes('lowdefy.yml'));
|
|
26
|
+
if (lowdefyYamlModified) {
|
|
27
|
+
const lowdefyVersion = await getLowdefyVersion(context);
|
|
28
|
+
if (lowdefyVersion !== context.version && lowdefyVersion !== 'local') {
|
|
29
|
+
context.shutdownServer();
|
|
30
|
+
console.warn('Lowdefy version changed. You should restart your development server.');
|
|
31
|
+
process.exit();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
await context.lowdefyBuild();
|
|
36
|
+
context.reloadClients();
|
|
37
|
+
};
|
|
38
|
+
return setupWatcher({
|
|
39
|
+
callback,
|
|
40
|
+
ignorePaths: context.options.watchIgnore,
|
|
41
|
+
watchPaths: [context.directories.config, ...context.options.watch],
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export default lowdefyBuildWatcher;
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2020-2021 Lowdefy, Inc
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/* eslint-disable no-console */
|
|
17
|
+
|
|
18
|
+
import crypto from 'crypto';
|
|
19
|
+
import path from 'path';
|
|
20
|
+
import { readFile } from '@lowdefy/node-utils';
|
|
21
|
+
import setupWatcher from '../utils/setupWatcher.mjs';
|
|
22
|
+
|
|
23
|
+
const hashes = {};
|
|
24
|
+
|
|
25
|
+
const watchedFiles = [
|
|
26
|
+
'build/config.json',
|
|
27
|
+
'build/plugins/blocks.js',
|
|
28
|
+
'build/plugins/connections.js',
|
|
29
|
+
'build/plugins/icons.js',
|
|
30
|
+
'build/plugins/operatorsClient.js',
|
|
31
|
+
'build/plugins/operatorsServer.js',
|
|
32
|
+
'build/plugins/styles.less',
|
|
33
|
+
'package.json',
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
async function sha1(filePath) {
|
|
37
|
+
const content = await readFile(filePath);
|
|
38
|
+
return crypto
|
|
39
|
+
.createHash('sha1')
|
|
40
|
+
.update(content || '')
|
|
41
|
+
.digest('hex');
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
async function nextBuildWatcher(context) {
|
|
45
|
+
// Initialize hashes so that app does not rebuild the first time
|
|
46
|
+
// Lowdefy build is run.
|
|
47
|
+
await Promise.all(
|
|
48
|
+
watchedFiles.map(async (filePath) => {
|
|
49
|
+
const fullPath = path.resolve(context.directories.server, filePath);
|
|
50
|
+
hashes[fullPath] = await sha1(fullPath);
|
|
51
|
+
})
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
const callback = async (filePaths) => {
|
|
55
|
+
let install = false;
|
|
56
|
+
let build = false;
|
|
57
|
+
await Promise.all(
|
|
58
|
+
filePaths.flat().map(async (filePath) => {
|
|
59
|
+
const hash = await sha1(filePath);
|
|
60
|
+
if (hashes[filePath] === hash) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
build = true;
|
|
64
|
+
if (filePath.endsWith('package.json')) {
|
|
65
|
+
install = true;
|
|
66
|
+
}
|
|
67
|
+
hashes[filePath] = hash;
|
|
68
|
+
})
|
|
69
|
+
);
|
|
70
|
+
|
|
71
|
+
if (!build) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
context.shutdownServer();
|
|
76
|
+
if (install) {
|
|
77
|
+
await context.installPlugins();
|
|
78
|
+
}
|
|
79
|
+
await context.nextBuild();
|
|
80
|
+
context.restartServer();
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
return setupWatcher({
|
|
84
|
+
callback,
|
|
85
|
+
watchPaths: [
|
|
86
|
+
path.join(context.directories.build, 'plugins'),
|
|
87
|
+
path.join(context.directories.build, 'config.json'),
|
|
88
|
+
path.join(context.directories.server, 'package.json'),
|
|
89
|
+
],
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export default nextBuildWatcher;
|
package/src/pages/_app.js
CHANGED
|
@@ -22,12 +22,14 @@ import LowdefyContext from '../components/LowdefyContext.js';
|
|
|
22
22
|
|
|
23
23
|
import '../../build/plugins/styles.less';
|
|
24
24
|
|
|
25
|
+
const lowdefy = {};
|
|
26
|
+
|
|
25
27
|
function App({ Component, pageProps }) {
|
|
26
28
|
return (
|
|
27
29
|
<ErrorBoundary>
|
|
28
30
|
<Suspense>
|
|
29
|
-
<LowdefyContext>
|
|
30
|
-
|
|
31
|
+
<LowdefyContext lowdefy={lowdefy}>
|
|
32
|
+
<Component lowdefy={lowdefy} {...pageProps} />
|
|
31
33
|
</LowdefyContext>
|
|
32
34
|
</Suspense>
|
|
33
35
|
</ErrorBoundary>
|
package/src/pages/api/reload.js
CHANGED
|
@@ -14,8 +14,6 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
// TODO: Send keep-alive comment event: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#examples
|
|
18
|
-
|
|
19
17
|
import chokidar from 'chokidar';
|
|
20
18
|
|
|
21
19
|
const handler = async (req, res) => {
|
|
@@ -25,6 +25,7 @@ export default async function handler(req, res) {
|
|
|
25
25
|
throw new Error('Only POST requests are supported.');
|
|
26
26
|
}
|
|
27
27
|
// TODO: configure API context
|
|
28
|
+
// TODO: configure build directory?
|
|
28
29
|
const apiContext = await createApiContext({
|
|
29
30
|
buildDirectory: './build',
|
|
30
31
|
connections,
|
package/src/utils/callRequest.js
CHANGED
|
@@ -16,9 +16,9 @@
|
|
|
16
16
|
|
|
17
17
|
import request from './request.js';
|
|
18
18
|
|
|
19
|
-
function callRequest({ pageId, payload, requestId }) {
|
|
19
|
+
function callRequest(apiContext, { pageId, payload, requestId }) {
|
|
20
20
|
return request({
|
|
21
|
-
url:
|
|
21
|
+
url: `${apiContext.config.basePath}/api/request/${pageId}/${requestId}`,
|
|
22
22
|
method: 'POST',
|
|
23
23
|
body: { payload },
|
|
24
24
|
});
|
package/src/utils/setPageId.js
CHANGED
|
@@ -15,18 +15,18 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
function setPageId(lowdefy) {
|
|
18
|
-
if (lowdefy._internal.pathname ===
|
|
18
|
+
if (lowdefy._internal.router.pathname === `/404`) {
|
|
19
19
|
lowdefy.pageId = '404';
|
|
20
20
|
return false;
|
|
21
21
|
}
|
|
22
|
-
if (!lowdefy._internal.query.pageId) {
|
|
22
|
+
if (!lowdefy._internal.router.query.pageId) {
|
|
23
23
|
lowdefy.pageId = lowdefy.home.pageId;
|
|
24
24
|
if (lowdefy.home.configured === false) {
|
|
25
25
|
return true;
|
|
26
26
|
}
|
|
27
27
|
return false;
|
|
28
28
|
}
|
|
29
|
-
lowdefy.pageId = lowdefy._internal.query.pageId;
|
|
29
|
+
lowdefy.pageId = lowdefy._internal.router.query.pageId;
|
|
30
30
|
return false;
|
|
31
31
|
}
|
|
32
32
|
|
package/src/utils/setupLink.js
CHANGED
|
@@ -16,29 +16,37 @@
|
|
|
16
16
|
|
|
17
17
|
import { createLink } from '@lowdefy/engine';
|
|
18
18
|
|
|
19
|
-
function setupLink(
|
|
19
|
+
function setupLink(lowdefy) {
|
|
20
20
|
const { router, window } = lowdefy._internal;
|
|
21
|
-
const
|
|
21
|
+
const backLink = () => router.back();
|
|
22
|
+
const disabledLink = () => {};
|
|
23
|
+
const newOriginLink = ({ url, query, newTab }) => {
|
|
22
24
|
if (newTab) {
|
|
23
|
-
return window.open(`${
|
|
25
|
+
return window.open(`${url}${query ? `?${query}` : ''}`, '_blank').focus();
|
|
24
26
|
} else {
|
|
25
|
-
|
|
26
|
-
return router.push({
|
|
27
|
-
pathname: path,
|
|
28
|
-
// TODO: Do we handle urlQuery as a param here?
|
|
29
|
-
// query: {},
|
|
30
|
-
});
|
|
27
|
+
return window.location.assign(`${url}${query ? `?${query}` : ''}`);
|
|
31
28
|
}
|
|
32
29
|
};
|
|
33
|
-
const
|
|
30
|
+
const sameOriginLink = ({ newTab, pathname, query, setInput }) => {
|
|
34
31
|
if (newTab) {
|
|
35
|
-
return window
|
|
32
|
+
return window
|
|
33
|
+
.open(
|
|
34
|
+
`${window.location.origin}${lowdefy.basePath}${pathname}${query ? `?${query}` : ''}`,
|
|
35
|
+
'_blank'
|
|
36
|
+
)
|
|
37
|
+
.focus();
|
|
36
38
|
} else {
|
|
37
|
-
|
|
39
|
+
setInput();
|
|
40
|
+
return router.push({
|
|
41
|
+
pathname,
|
|
42
|
+
query,
|
|
43
|
+
});
|
|
38
44
|
}
|
|
39
45
|
};
|
|
40
|
-
const
|
|
41
|
-
|
|
46
|
+
const noLink = () => {
|
|
47
|
+
throw new Error(`Invalid Link.`);
|
|
48
|
+
};
|
|
49
|
+
return createLink({ backLink, disabledLink, lowdefy, newOriginLink, noLink, sameOriginLink });
|
|
42
50
|
}
|
|
43
51
|
|
|
44
52
|
export default setupLink;
|
|
@@ -16,13 +16,13 @@
|
|
|
16
16
|
|
|
17
17
|
import { useSWRConfig } from 'swr';
|
|
18
18
|
|
|
19
|
-
function useMutateCache() {
|
|
19
|
+
function useMutateCache(basePath) {
|
|
20
20
|
const { cache, mutate } = useSWRConfig();
|
|
21
21
|
return () => {
|
|
22
|
-
const keys = [
|
|
22
|
+
const keys = [`${basePath}/api/root`];
|
|
23
23
|
|
|
24
24
|
for (const key of cache.keys()) {
|
|
25
|
-
if (key.startsWith(
|
|
25
|
+
if (key.startsWith(`${basePath}/api/page`)) {
|
|
26
26
|
keys.push(key);
|
|
27
27
|
}
|
|
28
28
|
}
|
|
@@ -21,11 +21,8 @@ function fetchPageConfig(url) {
|
|
|
21
21
|
return request({ url });
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function usePageConfig(pageId) {
|
|
25
|
-
|
|
26
|
-
pageId = 'NULL';
|
|
27
|
-
}
|
|
28
|
-
const { data } = useSWR(`/api/page/${pageId}`, fetchPageConfig, { suspense: true });
|
|
24
|
+
function usePageConfig(pageId, basePath) {
|
|
25
|
+
const { data } = useSWR(`${basePath}/api/page/${pageId}`, fetchPageConfig, { suspense: true });
|
|
29
26
|
return { data };
|
|
30
27
|
}
|
|
31
28
|
|
|
@@ -17,12 +17,12 @@ import request from './request.js';
|
|
|
17
17
|
|
|
18
18
|
// TODO: Handle TokenExpiredError
|
|
19
19
|
|
|
20
|
-
function fetchRootConfig() {
|
|
21
|
-
return request({ url
|
|
20
|
+
function fetchRootConfig(url) {
|
|
21
|
+
return request({ url });
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
function useRootConfig() {
|
|
25
|
-
const { data } = useSWR(
|
|
24
|
+
function useRootConfig(basePath) {
|
|
25
|
+
const { data } = useSWR(`${basePath}/api/root`, fetchRootConfig, { suspense: true });
|
|
26
26
|
return { data };
|
|
27
27
|
}
|
|
28
28
|
|