mirror of
https://github.com/HeyPuter/puter.git
synced 2026-05-03 16:10:31 +00:00
devex: rollup via module instead of subprocess
This commit is contained in:
@@ -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',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user