mirror of
https://github.com/lowdefy/lowdefy.git
synced 2025-02-17 14:30:34 +08:00
feat(server-dev): Dev server plugin install and next build working.
This commit is contained in:
parent
a6f39fbcd0
commit
cf66a6f839
@ -14,15 +14,13 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import startServerProcess from './startServerProcess.mjs';
|
||||
import startNextServer from './startNextServer.mjs';
|
||||
|
||||
function restartServer(context) {
|
||||
return async () => {
|
||||
if (context.serverProcess) {
|
||||
console.log('Restarting server...');
|
||||
context.serverProcess.kill();
|
||||
startServerProcess(context);
|
||||
}
|
||||
return () => {
|
||||
context.shutdownServer(); // Is this needed here?
|
||||
console.log('Restarting server...');
|
||||
startNextServer(context);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -15,10 +15,19 @@
|
||||
*/
|
||||
|
||||
function shutdownServer(context) {
|
||||
return async () => {
|
||||
return () => {
|
||||
if (context.serverProcess) {
|
||||
console.log('Shutting down server...');
|
||||
context.serverProcess.kill();
|
||||
// console.log(
|
||||
// `Existing server ${context.serverProcess.pid}, killed: ${context.serverProcess.killed}`
|
||||
// );
|
||||
if (!context.serverProcess.killed) {
|
||||
console.log('Shutting down server...');
|
||||
context.serverProcess.kill();
|
||||
// console.log(
|
||||
// `Killed server ${context.serverProcess.pid}, killed: ${context.serverProcess.killed}`
|
||||
// );
|
||||
}
|
||||
context.serverProcess = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
@ -14,13 +14,18 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { createRequire } from 'module';
|
||||
import spawnProcess from '../utils/spawnProcess.mjs';
|
||||
|
||||
const require = createRequire(import.meta.url);
|
||||
|
||||
function startServerProcess(context) {
|
||||
context.serverProcess = spawnProcess({
|
||||
context.shutdownServer();
|
||||
const nextCliUrl = require.resolve('next').replace('server/next.js', 'bin/next');
|
||||
const nextServer = spawnProcess({
|
||||
logger: console,
|
||||
command: context.packageManager,
|
||||
args: ['run', 'next', 'start'],
|
||||
command: 'node',
|
||||
args: [nextCliUrl, 'start'],
|
||||
silent: false,
|
||||
processOptions: {
|
||||
env: {
|
||||
@ -30,12 +35,14 @@ function startServerProcess(context) {
|
||||
},
|
||||
},
|
||||
});
|
||||
context.serverProcess.on('exit', (code) => {
|
||||
if (code !== 0) {
|
||||
context.serverProcessPromise.reject(new Error('Server error.'));
|
||||
}
|
||||
context.serverProcessPromise.resolve();
|
||||
// console.log(`Started server ${nextServer.pid}.`);
|
||||
// nextServer.on('exit', (code, signal) => {
|
||||
// console.log(`nextServer exit ${nextServer.pid}, signal: ${signal}, code: ${code}`);
|
||||
// });
|
||||
nextServer.on('error', (error) => {
|
||||
console.log(error);
|
||||
});
|
||||
context.nextServer = nextServer;
|
||||
}
|
||||
|
||||
export default startServerProcess;
|
@ -15,14 +15,14 @@
|
||||
*/
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import startServerProcess from './startServerProcess.mjs';
|
||||
import startNextServer from './startNextServer.mjs';
|
||||
|
||||
async function startServer(context) {
|
||||
return new Promise((resolve, reject) => {
|
||||
context.serverProcessPromise = { resolve, reject };
|
||||
try {
|
||||
startServerProcess(context);
|
||||
startNextServer(context);
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
|
@ -14,50 +14,17 @@
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
import configWatcher from '../watchers/configWatcher.mjs';
|
||||
import envWatcher from '../watchers/envWatcher.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.
|
||||
*/
|
||||
import lowdefyBuildWatcher from '../watchers/lowdefyBuildWatcher.mjs';
|
||||
import nextBuildWatcher from '../watchers/nextBuildWatcher.mjs';
|
||||
|
||||
function startWatchers(context) {
|
||||
return async () => {
|
||||
await Promise.all([configWatcher(context), envWatcher(context)]);
|
||||
await Promise.all([
|
||||
envWatcher(context),
|
||||
lowdefyBuildWatcher(context),
|
||||
nextBuildWatcher(context),
|
||||
]);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ async function run() {
|
||||
opener(`http://localhost:${context.port}`);
|
||||
await serverPromise;
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
context.shutdownServer();
|
||||
throw error;
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
||||
import path from 'path';
|
||||
import setupWatcher from '../utils/setupWatcher.mjs';
|
||||
|
||||
async function envWatcher(context) {
|
||||
function envWatcher(context) {
|
||||
const callback = async () => {
|
||||
console.warn('.env file changed.');
|
||||
await context.readDotEnv();
|
||||
|
@ -18,14 +18,15 @@
|
||||
import getLowdefyVersion from '../utils/getLowdefyVersion.mjs';
|
||||
import setupWatcher from '../utils/setupWatcher.mjs';
|
||||
|
||||
async function configWatcher(context) {
|
||||
function lowdefyBuildWatcher(context) {
|
||||
const callback = async (filePaths) => {
|
||||
const lowdefyYamlModified = filePaths
|
||||
.flat()
|
||||
.some((filePath) => filePath.includes('lowdefy.yaml') || filePath.includes('lowdefy.yml'));
|
||||
if (lowdefyYamlModified) {
|
||||
const lowdefyVersion = await getLowdefyVersion(context);
|
||||
if (lowdefyVersion !== context.version || lowdefyVersion === 'local') {
|
||||
if (lowdefyVersion !== context.version && lowdefyVersion !== 'local') {
|
||||
context.shutdownServer();
|
||||
console.warn('Lowdefy version changed. You should restart your development server.');
|
||||
process.exit();
|
||||
}
|
||||
@ -35,7 +36,10 @@ async function configWatcher(context) {
|
||||
context.reloadClients();
|
||||
};
|
||||
// TODO: Add ignored and watch paths
|
||||
return setupWatcher({ callback, watchPaths: [context.directories.config] });
|
||||
return setupWatcher({
|
||||
callback,
|
||||
watchPaths: [context.directories.config],
|
||||
});
|
||||
}
|
||||
|
||||
export default configWatcher;
|
||||
export default lowdefyBuildWatcher;
|
@ -0,0 +1,87 @@
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import crypto from 'crypto';
|
||||
import path from 'path';
|
||||
import { readFile } from '@lowdefy/node-utils';
|
||||
import setupWatcher from '../utils/setupWatcher.mjs';
|
||||
|
||||
const hashes = {};
|
||||
|
||||
const watchedFiles = [
|
||||
'build/config.json',
|
||||
'build/plugins/blocks.js',
|
||||
'build/plugins/connections.js',
|
||||
'build/plugins/icons.js',
|
||||
'build/plugins/operatorsClient.js',
|
||||
'build/plugins/operatorsServer.js',
|
||||
'build/plugins/styles.less',
|
||||
'package.json',
|
||||
];
|
||||
|
||||
async function sha1(filePath) {
|
||||
const content = await readFile(filePath);
|
||||
return crypto
|
||||
.createHash('sha1')
|
||||
.update(content || '')
|
||||
.digest('hex');
|
||||
}
|
||||
|
||||
async function nextBuildWatcher(context) {
|
||||
// Initialize hashes so that app does not rebuild the first time
|
||||
// Lowdefy build is run.
|
||||
await Promise.all(
|
||||
watchedFiles.map(async (filePath) => {
|
||||
const fullPath = path.resolve(context.directories.server, filePath);
|
||||
hashes[fullPath] = await sha1(fullPath);
|
||||
})
|
||||
);
|
||||
|
||||
const callback = async (filePaths) => {
|
||||
let install = false;
|
||||
let build = false;
|
||||
await Promise.all(
|
||||
filePaths.flat().map(async (filePath) => {
|
||||
const hash = await sha1(filePath);
|
||||
if (hashes[filePath] === hash) return;
|
||||
build = true;
|
||||
if (filePath.endsWith('package.json')) install = true;
|
||||
hashes[filePath] = hash;
|
||||
})
|
||||
);
|
||||
|
||||
if (!build) return;
|
||||
|
||||
context.shutdownServer();
|
||||
if (install) {
|
||||
await context.installPlugins();
|
||||
}
|
||||
await context.nextBuild();
|
||||
context.restartServer();
|
||||
};
|
||||
|
||||
return setupWatcher({
|
||||
callback,
|
||||
watchPaths: [
|
||||
path.join(context.directories.build, 'plugins'),
|
||||
path.join(context.directories.build, 'config.json'),
|
||||
path.join(context.directories.server, 'package.json'),
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
export default nextBuildWatcher;
|
Loading…
Reference in New Issue
Block a user