devex: rollup via module instead of subprocess

This commit is contained in:
KernelDeimos
2025-10-09 14:31:19 -04:00
committed by Eric Dubé
parent 1449d12b0e
commit 360082d8bd
2 changed files with 133 additions and 53 deletions
@@ -21,6 +21,7 @@ const BaseService = require("../../services/BaseService");
const path_ = require('node:path');
const fs = require('node:fs');
const rollupModule = require("rollup");
class ProxyLogger {
constructor (log) {
@@ -69,7 +70,10 @@ class DevWatcherService extends BaseService {
async ['__on_ready.webserver'] () {
const svc_process = this.services.get('process');
const { root, commands, webpack } = this.args;
let { root, commands, webpack, rollup } = this.args;
if ( ! webpack ) webpack = [];
if ( ! rollup ) rollup = [];
let promises = [];
for ( const entry of commands ) {
const { directory } = entry;
@@ -82,49 +86,67 @@ class DevWatcherService extends BaseService {
const p = this.start_a_webpack_watcher_(entry);
promises.push(p);
}
for ( const entry of rollup ) {
const p = this.start_a_rollup_watcher_(entry);
promises.push(p);
}
await Promise.all(promises);
// It's difficult to tell when webpack is "done" its first
// run so we just wait a bit before we say we're ready.
await new Promise((resolve) => setTimeout(resolve, 5000));
}
async start_a_webpack_watcher_ (entry) {
let webpackConfigPath, moduleType; {
const possibleWebpackConfigNames = [
['webpack.config.js', 'package.json'],
['webpack.config.cjs', 'commonjs'],
['webpack.config.mjs', 'module'],
];
for ( const [configName, supposedModuleType] of possibleWebpackConfigNames ) {
// There isn't really an async fs.exists() funciton. I assume this
// is because 'exists' is already a very fast operation.
const supposedPath = path_.join(this.args.root, entry.directory, configName);
if ( fs.existsSync(supposedPath) ) {
webpackConfigPath = supposedPath;
moduleType = supposedModuleType;
break;
}
async get_configjs ({ directory, configIsFor, possibleConfigNames }) {
let configjsPath, moduleType;
for ( const [configName, supposedModuleType] of possibleConfigNames ) {
// There isn't really an async fs.exists() funciton. I assume this
// is because 'exists' is already a very fast operation.
const supposedPath = path_.join(this.args.root, directory, configName);
if ( fs.existsSync(supposedPath) ) {
configjsPath = supposedPath;
moduleType = supposedModuleType;
break;
}
}
if ( ! webpackConfigPath ) {
throw new Error(`could not find webpack config for: ${entry.directory}`);
if ( ! configjsPath ) {
throw new Error(`could not find ${configIsFor} config for: ${directory}`);
}
// If the webpack config ends with .js it could be an ES6 module or a
// CJS module, so the absolute safest thing to do so as not to completely
// break in specific patch version of supported versions of node.js is
// to read the package.json and see what it says is the import mechanism.
if ( moduleType === 'package.json' ) {
const packageJSONPath = path_.join(this.args.root, entry.directory, 'package.json');
const packageJSONPath = path_.join(this.args.root, directory, 'package.json');
const packageJSONObject = JSON.parse(fs.readFileSync(packageJSONPath));
moduleType = packageJSONObject?.type ?? 'module';
}
return {
configjsPath,
moduleType,
};
}
async start_a_webpack_watcher_ (entry) {
const possibleConfigNames = [
['webpack.config.js', 'package.json'],
['webpack.config.cjs', 'commonjs'],
['webpack.config.mjs', 'module'],
];
const {
configjsPath: webpackConfigPath,
moduleType,
} = await this.get_configjs({
directory: entry.directory,
configIsFor: 'webpack', // for error message
possibleConfigNames,
});
let oldEnv;
if ( entry.env ) {
@@ -169,6 +191,75 @@ class DevWatcherService extends BaseService {
}
});
}
async start_a_rollup_watcher_ (entry) {
const possibleConfigNames = [
['rollup.config.js', 'package.json'],
['rollup.config.cjs', 'commonjs'],
['rollup.config.mjs', 'module'],
];
const {
configjsPath: rollupConfigPath,
moduleType,
} = await this.get_configjs({
directory: entry.directory,
configIsFor: 'rollup', // for error message
possibleConfigNames,
});
const updateRollupPaths = (config, newBase) => {
const onoutput = o => ({ ...o, file: o.file ? path_.join(newBase, o.file) : o.file });
return {
...config,
input: path_.join(newBase, config.input),
output: Array.isArray(config.output)
? config.output.map(onoutput)
: onoutput(config.output),
};
};
let oldEnv;
if ( entry.env ) {
oldEnv = process.env;
const newEnv = Object.create(process.env);
for ( const k in entry.env ) {
newEnv[k] = entry.env[k];
}
process.env = newEnv; // Yep, it totally lets us do this
}
let rollupConfig = moduleType === 'module'
? (await import(rollupConfigPath)).default
: require(rollupConfigPath);
if ( oldEnv ) process.env = oldEnv;
rollupConfig = updateRollupPaths(
rollupConfig,
path_.join(this.args.root, entry.directory),
);
// rollupConfig.watch = true; // I mean why can't it just...
const watcher = rollupModule.watch(rollupConfig);
let errorAfterLastEnd = false;
watcher.on('event', (event) => {
if ( event.code === 'END' ) {
if ( errorAfterLastEnd ) {
errorAfterLastEnd = false;
return;
}
this.log.info(`✅ updated ${entry.directory} using Rollup`);
} else if ( event.code === 'ERROR' ) {
this.log.error(`error information: ${entry.directory} using Rollup`, {
event,
});
this.log.error(`❌ failed to update ${entry.directory} using Rollup`);
errorAfterLastEnd = true;
}
});
}
};
module.exports = DevWatcherService;
@@ -51,6 +51,22 @@ class SelfHostedModule extends AdvancedBase {
{
services.registerService('__dev-watcher', DevWatcherService, {
root: path_.resolve(__dirname, RELATIVE_PATH),
rollup: [
{
name: 'phoenix',
directory: 'src/phoenix',
env: {
PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js',
},
},
{
name: 'terminal',
directory: 'src/terminal',
env: {
PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js',
},
},
],
webpack: [
{
name: 'puter.js',
@@ -74,33 +90,6 @@ class SelfHostedModule extends AdvancedBase {
},
],
commands: [
{
name: 'terminal:rollup-watch',
directory: 'src/terminal',
command: 'npx',
args: ['rollup', '-c', 'rollup.config.js', '--watch'],
env: {
PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js',
},
},
{
name: 'phoenix:rollup-watch',
directory: 'src/phoenix',
command: 'npx',
args: ['rollup', '-c', 'rollup.config.js', '--watch'],
env: {
PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js',
},
},
{
name: 'git:rollup-watch',
directory: 'src/git',
command: 'npx',
args: ['rollup', '-c', 'rollup.config.js', '--watch'],
env: {
PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js',
},
},
],
});
}