Skip to content

Commit

Permalink
feat(connect): enabled support for config file
Browse files Browse the repository at this point in the history
  • Loading branch information
gpuente committed Oct 23, 2024
1 parent 16a9579 commit 7e5e316
Show file tree
Hide file tree
Showing 5 changed files with 214 additions and 103 deletions.
41 changes: 25 additions & 16 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
"build:service-worker": "tsc --build ./tsconfig.sw.json"
},
"dependencies": {
"commander": "^12.1.0",
"vite": "^5.4.8",
"vite-envs": "^4.4.5"
},
Expand Down
6 changes: 2 additions & 4 deletions studio/cli.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
#!/usr/bin/env node

import { startServer } from './index.js';
import { program } from './index.js';

startServer().catch(error => {
throw error;
});
program.parse(process.argv);
179 changes: 96 additions & 83 deletions studio/index.ts
Original file line number Diff line number Diff line change
@@ -1,89 +1,102 @@
import { exec } from 'node:child_process';
import { Command } from 'commander';
import fs from 'node:fs';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { createLogger, createServer, InlineConfig, Plugin } from 'vite';
import { viteEnvs } from 'vite-envs';
import { getStudioConfig, viteConnectDevStudioPlugin } from './vite-plugin';

const studioDirname = fileURLToPath(new URL('.', import.meta.url));
const appPath = join(studioDirname, '..');
const viteEnvsScript = join(appPath, 'vite-envs.sh');

// silences dynamic import warnings
const logger = createLogger();
// eslint-disable-next-line @typescript-eslint/unbound-method
const loggerWarn = logger.warn;
/**
* @param {string} msg
* @param {import('vite').LogOptions} options
*/
logger.warn = (msg, options) => {
if (msg.includes('The above dynamic import cannot be analyzed by Vite.')) {
return;
import { dirname, isAbsolute, join, resolve } from 'node:path';

import { startServer } from './server';

type PowerhouseConfig = {
documentModelsDir?: string;
editorsDir?: string;
};

const readJsonFile = (filePath: string): PowerhouseConfig | null => {
try {
const absolutePath = resolve(filePath);
const fileContents = fs.readFileSync(absolutePath, 'utf-8');
return JSON.parse(fileContents) as PowerhouseConfig;
} catch (error) {
console.error(`Error reading file: ${filePath}`);
return null;
}
loggerWarn(msg, options);
};

function runShellScriptPlugin(scriptPath: string): Plugin {
return {
name: 'vite-plugin-run-shell-script',
buildStart() {
if (fs.existsSync(scriptPath)) {
exec(`sh ${scriptPath}`, (error, stdout, stderr) => {
if (error) {
console.error(
`Error executing the script: ${error.message}`,
);
return;
}
if (stderr) {
console.error(stderr);
}
});
}
},
};
}

export async function startServer() {
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3000;
const studioConfig = getStudioConfig();

// needed for viteEnvs
if (!fs.existsSync(join(appPath, 'src'))) {
fs.mkdirSync(join(appPath, 'src'));
type ConnectStudioOptions = {
port?: string;
host?: boolean;
configFile?: string;
localEditors?: string;
localDocuments?: string;
};

type ConnectStudioAction = (options: ConnectStudioOptions) => void;

const connectStudioAction: ConnectStudioAction = options => {
if (options.port) {
process.env.PORT = options.port;
}

if (options.host) {
process.env.HOST = options.host.toString();
}

if (options.configFile) {
const config = readJsonFile(options.configFile);
if (!config) return;

const configFileDir = dirname(options.configFile);

if (config.documentModelsDir) {
process.env.LOCAL_DOCUMENT_MODELS = isAbsolute(
config.documentModelsDir,
)
? config.documentModelsDir
: join(configFileDir, config.documentModelsDir);
}

if (config.editorsDir) {
process.env.LOCAL_DOCUMENT_EDITORS = isAbsolute(config.editorsDir)
? config.editorsDir
: join(configFileDir, config.editorsDir);
}
}

process.env.PH_CONNECT_STUDIO_MODE = 'true';

const config: InlineConfig = {
customLogger: logger,
configFile: false,
root: appPath,
server: {
port: PORT,
open: true,
},
plugins: [
viteConnectDevStudioPlugin(true),
viteEnvs({
declarationFile: join(studioDirname, '../.env'),
computedEnv: studioConfig,
}),
runShellScriptPlugin(viteEnvsScript),
],
build: {
rollupOptions: {
input: 'index.html',
},
},
};

const server = await createServer(config);

await server.listen();

server.printUrls();
server.bindCLIShortcuts({ print: true });
}
if (options.localEditors) {
process.env.LOCAL_DOCUMENT_EDITORS = options.localEditors;
}

if (options.localDocuments) {
process.env.LOCAL_DOCUMENT_MODELS = options.localDocuments;
}

startServer().catch(error => {
throw error;
});
};

export const program = new Command();

program
.name('Connect Studio')
.description('Connect Studio CLI')
.option('-p, --port <port>', 'Port to run the server on', '3000')
.option('-h, --host', 'Expose the server to the network')
.option(
'--config-file <configFile>',
'Path to the powerhouse.config.js file',
)
.option(
'-le, --local-editors <localEditors>',
'Link local document editors path',
)
.option(
'-ld, --local-documents <localDocuments>',
'Link local documents path',
)
.action(connectStudioAction);

program
.command('help')
.description('Display help information')
.action(() => {
program.help();
});
90 changes: 90 additions & 0 deletions studio/server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import { exec } from 'node:child_process';
import fs from 'node:fs';
import { join } from 'node:path';
import { fileURLToPath } from 'node:url';
import { createLogger, createServer, InlineConfig, Plugin } from 'vite';
import { viteEnvs } from 'vite-envs';
import { getStudioConfig, viteConnectDevStudioPlugin } from './vite-plugin';

const studioDirname = fileURLToPath(new URL('.', import.meta.url));
const appPath = join(studioDirname, '..');
const viteEnvsScript = join(appPath, 'vite-envs.sh');

// silences dynamic import warnings
const logger = createLogger();
// eslint-disable-next-line @typescript-eslint/unbound-method
const loggerWarn = logger.warn;
/**
* @param {string} msg
* @param {import('vite').LogOptions} options
*/
logger.warn = (msg, options) => {
if (msg.includes('The above dynamic import cannot be analyzed by Vite.')) {
return;
}
loggerWarn(msg, options);
};

function runShellScriptPlugin(scriptPath: string): Plugin {
return {
name: 'vite-plugin-run-shell-script',
buildStart() {
if (fs.existsSync(scriptPath)) {
exec(`sh ${scriptPath}`, (error, stdout, stderr) => {
if (error) {
console.error(
`Error executing the script: ${error.message}`,
);
return;
}
if (stderr) {
console.error(stderr);
}
});
}
},
};
}

export async function startServer() {
const PORT = process.env.PORT ? parseInt(process.env.PORT) : 3000;
const studioConfig = getStudioConfig();

// needed for viteEnvs
if (!fs.existsSync(join(appPath, 'src'))) {
fs.mkdirSync(join(appPath, 'src'));
}

process.env.PH_CONNECT_STUDIO_MODE = 'true';

const config: InlineConfig = {
customLogger: logger,
configFile: false,
root: appPath,
server: {
port: PORT,
open: true,
host: Boolean(process.env.HOST),
},
plugins: [
viteConnectDevStudioPlugin(true),
viteEnvs({
declarationFile: join(studioDirname, '../.env'),
computedEnv: studioConfig,
}),
runShellScriptPlugin(viteEnvsScript),
],
build: {
rollupOptions: {
input: 'index.html',
},
},
};

const server = await createServer(config);

await server.listen();

server.printUrls();
server.bindCLIShortcuts({ print: true });
}

0 comments on commit 7e5e316

Please sign in to comment.