mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-04-06 15:30:30 +08:00
feat(server-dev): Add the abilty to restart the dev server.
This commit is contained in:
parent
77cd297117
commit
b610a63a52
@ -132,7 +132,6 @@ test('BatchChanges calls function again if it receives new change while executin
|
||||
expect(fn).toHaveBeenCalledTimes(1);
|
||||
await wait(50);
|
||||
expect(fn).toHaveBeenCalledTimes(2);
|
||||
await wait(50);
|
||||
});
|
||||
|
||||
test('BatchChanges provides arguments to the called function', async () => {
|
||||
|
@ -16,14 +16,16 @@
|
||||
|
||||
class BatchChanges {
|
||||
constructor({ fn, minDelay }) {
|
||||
this.args = [];
|
||||
this.fn = fn;
|
||||
this.delay = minDelay || 500;
|
||||
this.minDelay = minDelay || 500;
|
||||
this._call = this._call.bind(this);
|
||||
this.args = [];
|
||||
this.delay = minDelay || 500;
|
||||
this.fn = fn;
|
||||
this.minDelay = minDelay || 500;
|
||||
this.repeat = false;
|
||||
this.running = false;
|
||||
}
|
||||
|
||||
newChange(args) {
|
||||
newChange(...args) {
|
||||
this.args.push(args);
|
||||
this.delay = this.minDelay;
|
||||
this._startTimer();
|
||||
@ -33,18 +35,29 @@ class BatchChanges {
|
||||
if (this.timer) {
|
||||
clearTimeout(this.timer);
|
||||
}
|
||||
this.timer = setTimeout(this._call, this.delay);
|
||||
if (this.running) {
|
||||
this.repeat = true;
|
||||
} else {
|
||||
this.timer = setTimeout(this._call, this.delay);
|
||||
}
|
||||
}
|
||||
|
||||
async _call() {
|
||||
this.running = true;
|
||||
try {
|
||||
const args = this.args;
|
||||
this.args = [];
|
||||
await this.fn(args);
|
||||
this.running = false;
|
||||
if (this.repeat) {
|
||||
this.repeat = false;
|
||||
this._call();
|
||||
}
|
||||
} catch (error) {
|
||||
this.running = false;
|
||||
console.error(error);
|
||||
this.delay *= 2;
|
||||
console.warn(`Retrying in ${this.delay / 1000}s.`, { timestamp: true });
|
||||
console.warn(`Retrying in ${this.delay / 1000}s.`);
|
||||
this._startTimer();
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ async function getContext() {
|
||||
config: path.resolve(configDirectory),
|
||||
},
|
||||
packageManager,
|
||||
restartServer: () => {},
|
||||
skipInstall,
|
||||
};
|
||||
return context;
|
||||
|
@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
Copyright 2020-2021 Lowdefy, Inc
|
||||
|
||||
@ -14,17 +15,15 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import runLowdefyBuild from './runLowdefyBuild.mjs';
|
||||
import runNextBuild from './runNextBuild.mjs';
|
||||
import installServer from './installServer.mjs';
|
||||
import installServer from './processes/installServer.mjs';
|
||||
import lowdefyBuild from './processes/lowdefyBuild.mjs';
|
||||
import nextBuild from './processes/nextBuild.mjs';
|
||||
|
||||
async function resetServer(context) {
|
||||
// TODO: Only install when needed
|
||||
async function initialBuild(context) {
|
||||
await installServer(context);
|
||||
await runLowdefyBuild(context);
|
||||
// TODO: Only install when needed
|
||||
await lowdefyBuild(context);
|
||||
await installServer(context);
|
||||
await runNextBuild(context);
|
||||
await nextBuild(context);
|
||||
}
|
||||
|
||||
export default resetServer;
|
||||
export default initialBuild;
|
@ -20,7 +20,7 @@ async function runLowdefyBuild({ packageManager, directories }) {
|
||||
await spawnProcess({
|
||||
logger: console,
|
||||
args: ['run', 'build:lowdefy'],
|
||||
command: packageManager || 'npm',
|
||||
command: packageManager,
|
||||
processOptions: {
|
||||
env: {
|
||||
...process.env,
|
@ -20,7 +20,7 @@ async function runNextBuild({ packageManager }) {
|
||||
await spawnProcess({
|
||||
logger: console,
|
||||
args: ['run', 'build:next'],
|
||||
command: packageManager || 'npm',
|
||||
command: packageManager,
|
||||
silent: false,
|
||||
});
|
||||
}
|
51
packages/server-dev/src/manager/processes/startServer.mjs
Normal file
51
packages/server-dev/src/manager/processes/startServer.mjs
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
Copyright 2020-2021 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import spawnKillableProcess from '../spawnKillableProcess.mjs';
|
||||
|
||||
function startServerProcess({ context, handleExit }) {
|
||||
context.serverProcess = spawnKillableProcess({
|
||||
logger: console,
|
||||
args: ['run', 'next', 'start'],
|
||||
command: context.packageManager,
|
||||
silent: false,
|
||||
});
|
||||
context.serverProcess.on('exit', handleExit);
|
||||
context.restartServer = async () => {
|
||||
context.serverProcess.kill();
|
||||
startServerProcess({ context, handleExit });
|
||||
};
|
||||
}
|
||||
|
||||
async function startServer(context) {
|
||||
return new Promise((resolve, reject) => {
|
||||
function handleExit(code) {
|
||||
if (code !== 0) {
|
||||
// TODO: Shutdown server
|
||||
reject(new Error('Server error.'));
|
||||
}
|
||||
resolve();
|
||||
}
|
||||
try {
|
||||
startServerProcess({ context, handleExit });
|
||||
} catch (error) {
|
||||
// TODO: Shutdown server
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default startServer;
|
@ -16,14 +16,14 @@
|
||||
*/
|
||||
|
||||
import getContext from './getContext.mjs';
|
||||
import resetServer from './resetServer.mjs';
|
||||
import setupFileWatchers from './setupFileWatchers.mjs';
|
||||
import startServer from './startServer.mjs';
|
||||
import initialBuild from './initialBuild.mjs';
|
||||
import startWatchers from './watchers/startWatchers.mjs';
|
||||
import startServer from './processes/startServer.mjs';
|
||||
|
||||
async function run() {
|
||||
const context = await getContext();
|
||||
await resetServer(context);
|
||||
await setupFileWatchers(context);
|
||||
await initialBuild(context);
|
||||
await startWatchers(context);
|
||||
await startServer(context);
|
||||
}
|
||||
|
||||
|
@ -1,23 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import setupConfigWatcher from './watchers/setupConfigWatcher.mjs';
|
||||
|
||||
async function setupWatchers(context) {
|
||||
await Promise.all([setupConfigWatcher(context)]);
|
||||
}
|
||||
|
||||
export default setupWatchers;
|
55
packages/server-dev/src/manager/spawnKillableProcess.mjs
Normal file
55
packages/server-dev/src/manager/spawnKillableProcess.mjs
Normal file
@ -0,0 +1,55 @@
|
||||
/*
|
||||
Copyright 2020-2021 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { spawn } from 'child_process';
|
||||
|
||||
function spawnKillableProcess({ logger, command, args, processOptions, silent }) {
|
||||
const process = spawn(command, args, processOptions);
|
||||
|
||||
process.stdout.on('data', (data) => {
|
||||
if (!silent) {
|
||||
data
|
||||
.toString('utf8')
|
||||
.split('\n')
|
||||
.forEach((line) => {
|
||||
if (line) {
|
||||
logger.log(line);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
process.stderr.on('data', (data) => {
|
||||
if (!silent) {
|
||||
data
|
||||
.toString('utf8')
|
||||
.split('\n')
|
||||
.forEach((line) => {
|
||||
if (line) {
|
||||
logger.warn(line);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
process.on('error', (error) => {
|
||||
throw error;
|
||||
});
|
||||
|
||||
return process;
|
||||
}
|
||||
|
||||
export default spawnKillableProcess;
|
@ -1,28 +0,0 @@
|
||||
/*
|
||||
Copyright 2020-2021 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { spawnProcess } from '@lowdefy/node-utils';
|
||||
|
||||
async function startServer({ packageManager }) {
|
||||
await spawnProcess({
|
||||
logger: console,
|
||||
args: ['run', 'next', 'start'],
|
||||
command: packageManager || 'npm',
|
||||
silent: false,
|
||||
});
|
||||
}
|
||||
|
||||
export default startServer;
|
@ -14,15 +14,16 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import runLowdefyBuild from '../runLowdefyBuild.mjs';
|
||||
import lowdefyBuild from '../processes/lowdefyBuild.mjs';
|
||||
import setupWatcher from './setupWatcher.mjs';
|
||||
|
||||
async function setupConfigWatcher(context) {
|
||||
async function configWatcher(context) {
|
||||
const callback = async () => {
|
||||
console.log('Running build');
|
||||
await runLowdefyBuild(context);
|
||||
await lowdefyBuild(context);
|
||||
context.restartServer();
|
||||
};
|
||||
// TODO: Add ignored paths
|
||||
return setupWatcher({ callback, watchPaths: [context.directories.config] });
|
||||
}
|
||||
|
||||
export default setupConfigWatcher;
|
||||
export default configWatcher;
|
63
packages/server-dev/src/manager/watchers/startWatchers.mjs
Normal file
63
packages/server-dev/src/manager/watchers/startWatchers.mjs
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
Copyright 2020-2021 Lowdefy, Inc
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import configWatcher from './configWatcher.mjs';
|
||||
|
||||
/*
|
||||
Config change
|
||||
Watch <config-dir>, <watch-dirs>, !<ignore-dirs>
|
||||
- Lowdefy build
|
||||
- Trigger soft reload
|
||||
----------------------------------------
|
||||
Install new plugin
|
||||
Watch <server>/package.json
|
||||
|
||||
- Install Server.
|
||||
- Next build.
|
||||
- No need for Lowdefy build (confirm?)
|
||||
- Trigger hard reload
|
||||
- Restart server.
|
||||
|
||||
----------------------------------------
|
||||
.env change
|
||||
Watch <config-dir>/.env
|
||||
- Trigger hard reload
|
||||
- Restart server.
|
||||
----------------------------------------
|
||||
Lowdefy version changed
|
||||
Watch <config-dir>/lowdefy.yaml
|
||||
- Warn and process.exit()
|
||||
----------------------------------------
|
||||
Style vars/app config change
|
||||
Watch <server-dir>/build/app.json
|
||||
Watch <server-dir>/build/config.json
|
||||
- Next build.
|
||||
- Trigger hard reload
|
||||
- Restart server.
|
||||
|
||||
----------------------------------------
|
||||
New plugin or icon used.
|
||||
Watch <server-dir>/build/plugins/*
|
||||
- Next build. (or dynamic import?)
|
||||
- Trigger hard reload
|
||||
- Restart server.
|
||||
*/
|
||||
|
||||
async function startWatchers(context) {
|
||||
await Promise.all([configWatcher(context)]);
|
||||
}
|
||||
|
||||
export default startWatchers;
|
Loading…
x
Reference in New Issue
Block a user