feat(server-dev): Add .env and lowdefy version watchers.

This commit is contained in:
Sam Tolmay 2022-01-21 12:26:52 +02:00
parent ad3511cce7
commit bc522684ab
No known key found for this signature in database
GPG Key ID: D004126FCD1A6DF0
17 changed files with 214 additions and 40 deletions

11
.pnp.cjs generated
View File

@ -5698,6 +5698,8 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
["@lowdefy/operators-yaml", "workspace:packages/plugins/operators/operators-yaml"],
["@next/eslint-plugin-next", "npm:12.0.4"],
["chokidar", "npm:3.5.2"],
["dotenv", "npm:14.2.0"],
["js-yaml", "npm:4.1.0"],
["less", "npm:4.1.2"],
["less-loader", "virtual:003bebd8b7a948d12b44e2c11a621884feb1891eea3645171e827971487f79396db9f7422bc411ccf3f90877e94ec86f5c3da70b96efb5daddb2ee3b35eae5c6#npm:10.2.0"],
["next", "virtual:003bebd8b7a948d12b44e2c11a621884feb1891eea3645171e827971487f79396db9f7422bc411ccf3f90877e94ec86f5c3da70b96efb5daddb2ee3b35eae5c6#npm:12.0.3"],
@ -10534,6 +10536,15 @@ function $$SETUP_STATE(hydrateRuntimeState, basePath) {
"linkType": "HARD",
}]
]],
["dotenv", [
["npm:14.2.0", {
"packageLocation": "./.yarn/cache/dotenv-npm-14.2.0-b237345d26-85a0e44918.zip/node_modules/dotenv/",
"packageDependencies": [
["dotenv", "npm:14.2.0"]
],
"linkType": "HARD",
}]
]],
["duplexer", [
["npm:0.1.2", {
"packageLocation": "./.yarn/cache/duplexer-npm-0.1.2-952c810235-62ba61a830.zip/node_modules/duplexer/",

Binary file not shown.

View File

@ -17,6 +17,7 @@
import { spawnProcess } from '@lowdefy/node-utils';
async function runDevServer({ context }) {
// TODO: Pass packageManager as option
await spawnProcess({
logger: context.print,
args: ['run', 'start'],

View File

@ -62,6 +62,8 @@
"@lowdefy/operators-uuid": "4.0.0-alpha.6",
"@lowdefy/operators-yaml": "4.0.0-alpha.6",
"chokidar": "3.5.2",
"dotenv": "14.2.0",
"js-yaml": "4.1.0",
"next": "12.0.3",
"next-auth": "4.0.0-beta.6",
"opener": "1.5.2",

View File

@ -18,13 +18,16 @@
import path from 'path';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import { readFile } from '@lowdefy/node-utils';
import initialBuild from './processes/initialBuild.mjs';
import installPlugins from './processes/installPlugins.mjs';
import lowdefyBuild from './processes/lowdefyBuild.mjs';
import nextBuild from './processes/nextBuild.mjs';
import installPlugins from './processes/installPlugins.mjs';
import startServerProcess from './processes/startServerProcess.mjs';
import readDotEnv from './processes/readDotEnv.mjs';
import reloadClients from './processes/reloadClients.mjs';
import restartServer from './processes/restartServer.mjs';
import shutdownServer from './processes/shutdownServer.mjs';
import startWatchers from './processes/startWatchers.mjs';
const argv = yargs(hideBin(process.argv)).argv;
@ -39,30 +42,19 @@ async function getContext() {
server: process.cwd(),
},
packageManager,
restartServer: () => {
if (context.serverProcess) {
console.log('Restarting server...');
context.serverProcess.kill();
startServerProcess(context);
}
},
shutdownServer: () => {
if (context.serverProcess) {
console.log('Shutting down server...');
context.serverProcess.kill();
}
},
verbose,
};
const packageJson = JSON.parse(
await readFile(path.join(context.directories.server, 'package.json'))
);
context.version = packageJson.version;
context.version = process.env.npm_package_version;
context.initialBuild = initialBuild(context);
context.installPlugins = installPlugins(context);
context.lowdefyBuild = lowdefyBuild(context);
context.nextBuild = nextBuild(context);
context.readDotEnv = readDotEnv(context);
context.reloadClients = reloadClients(context);
context.restartServer = restartServer(context);
context.shutdownServer = shutdownServer(context);
context.startWatchers = startWatchers(context);
return context;
}

View File

@ -15,10 +15,13 @@
limitations under the License.
*/
async function initialBuild(context) {
await context.lowdefyBuild();
await context.installPlugins();
await context.nextBuild();
function initialBuild(context) {
return async () => {
await context.lowdefyBuild();
await context.installPlugins();
await context.nextBuild();
await context.readDotEnv();
};
}
export default initialBuild;

View File

@ -0,0 +1,28 @@
/*
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 path from 'path';
import dotenv from 'dotenv';
import { readFile } from '@lowdefy/node-utils';
function readDotEnv(context) {
return async () => {
const dotEnvPath = path.join(context.directories.config, '.env');
context.serverEnv = dotenv.parse(await readFile(dotEnvPath));
};
}
export default readDotEnv;

View File

@ -0,0 +1,29 @@
/*
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 startServerProcess from './startServerProcess.mjs';
function shutdownServer(context) {
return async () => {
if (context.serverProcess) {
console.log('Restarting server...');
context.serverProcess.kill();
startServerProcess(context);
}
};
}
export default shutdownServer;

View File

@ -0,0 +1,26 @@
/*
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.
*/
function shutdownServer(context) {
return async () => {
if (context.serverProcess) {
console.log('Shutting down server...');
context.serverProcess.kill();
}
};
}
export default shutdownServer;

View File

@ -22,6 +22,12 @@ function startServerProcess(context) {
command: context.packageManager,
args: ['run', 'next', 'start'],
silent: false,
processOptions: {
env: {
...process.env,
...context.serverEnv,
},
},
});
context.serverProcess.on('exit', (code) => {
if (code !== 0) {

View File

@ -14,8 +14,8 @@
limitations under the License.
*/
import configWatcher from './watchers/configWatcher.mjs';
import envWatcher from './watchers/envWatcher.mjs';
import configWatcher from '../watchers/configWatcher.mjs';
import envWatcher from '../watchers/envWatcher.mjs';
/*
Config change
@ -31,7 +31,6 @@ Watch <server>/package.json
- No need for Lowdefy build (confirm?)
- Trigger hard reload
- Restart server.
----------------------------------------
.env change
Watch <config-dir>/.env
@ -48,7 +47,6 @@ Watch <server-dir>/build/config.json
- Next build.
- Trigger hard reload
- Restart server.
----------------------------------------
New plugin or icon used.
Watch <server-dir>/build/plugins/*
@ -57,8 +55,10 @@ Watch <server-dir>/build/plugins/*
- Restart server.
*/
async function startWatchers(context) {
await Promise.all([configWatcher(context), envWatcher(context)]);
function startWatchers(context) {
return async () => {
await Promise.all([configWatcher(context), envWatcher(context)]);
};
}
export default startWatchers;

View File

@ -18,14 +18,12 @@
import { wait } from '@lowdefy/helpers';
import opener from 'opener';
import getContext from './getContext.mjs';
import initialBuild from './processes/initialBuild.mjs';
import startServer from './processes/startServer.mjs';
import startWatchers from './startWatchers.mjs';
async function run() {
const context = await getContext();
await initialBuild(context);
await startWatchers(context);
await context.initialBuild();
await context.startWatchers();
try {
const serverPromise = startServer(context);
await wait(800);

View 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 path from 'path';
import { type } from '@lowdefy/helpers';
import { readFile } from '@lowdefy/node-utils';
import YAML from 'js-yaml';
async function getLowdefyVersion(context) {
let lowdefyYaml = await readFile(path.join(context.directories.config, 'lowdefy.yaml'));
if (!lowdefyYaml) {
lowdefyYaml = await readFile(path.join(context.directories.config, 'lowdefy.yml'));
}
if (!lowdefyYaml) {
throw new Error(`Could not find "lowdefy.yaml" file.`);
}
let lowdefy;
try {
lowdefy = YAML.load(lowdefyYaml);
} catch (error) {
throw new Error(`Could not parse "lowdefy.yaml" file. Received error ${error.message}.`);
}
if (!lowdefy.lowdefy) {
throw new Error(
`No version specified in "lowdefy.yaml" file. Specify a version in the "lowdefy" field.`
);
}
if (!type.isString(lowdefy.lowdefy)) {
throw new Error(
`Version number specified in "lowdefy.yaml" file should be a string. Received ${JSON.stringify(
lowdefy.lowdefy
)}.`
);
}
return lowdefy.lowdefy;
}
export default getLowdefyVersion;

View File

@ -17,12 +17,18 @@
import chokidar from 'chokidar';
import BatchChanges from './BatchChanges.mjs';
function setupWatcher({ callback, watchDotfiles = false, ignorePaths = [], watchPaths }) {
function setupWatcher({
callback,
watchDotfiles = false,
ignorePaths = [],
watchPaths,
minDelay = 500,
}) {
return new Promise((resolve) => {
// const { watch = [], watchIgnore = [] } = context.options;
// const resolvedWatchPaths = watch.map((pathName) => path.resolve(pathName));
const batchChanges = new BatchChanges({ fn: callback, minDelay: 4000 });
const batchChanges = new BatchChanges({ fn: callback, minDelay });
const defaultIgnorePaths = watchDotfiles
? []
: [

View File

@ -13,12 +13,24 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
/* eslint-disable no-console */
import getLowdefyVersion from '../utils/getLowdefyVersion.mjs';
import setupWatcher from '../utils/setupWatcher.mjs';
async function configWatcher(context) {
const callback = async (...args) => {
console.log('args', args);
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) {
console.warn('Lowdefy version changed. You should restart your development server.');
process.exit();
}
}
await context.lowdefyBuild();
context.reloadClients();
};

View File

@ -13,8 +13,7 @@
See the License for the specific language governing permissions and
limitations under the License.
*/
import dotenv from 'dotenv';
/* eslint-disable no-console */
import path from 'path';
import setupWatcher from '../utils/setupWatcher.mjs';
@ -22,6 +21,7 @@ import setupWatcher from '../utils/setupWatcher.mjs';
async function envWatcher(context) {
const callback = async () => {
console.warn('.env file changed.');
await context.readDotEnv();
context.restartServer();
};
return setupWatcher({

View File

@ -3917,6 +3917,8 @@ __metadata:
"@lowdefy/operators-yaml": 4.0.0-alpha.6
"@next/eslint-plugin-next": 12.0.4
chokidar: 3.5.2
dotenv: 14.2.0
js-yaml: 4.1.0
less: 4.1.2
less-loader: 10.2.0
next: 12.0.3
@ -7943,6 +7945,13 @@ __metadata:
languageName: node
linkType: hard
"dotenv@npm:14.2.0":
version: 14.2.0
resolution: "dotenv@npm:14.2.0"
checksum: 85a0e44918ef49e64c278f757dab50a156b9a6ca67f708876fd81d265e575e35b67387fc681d910df99368d6c1edca66cd546edeb0f7db3b499cb876c999233e
languageName: node
linkType: hard
"duplexer@npm:^0.1.1":
version: 0.1.2
resolution: "duplexer@npm:0.1.2"