refactor: async

This commit is contained in:
cha0s 2022-03-01 10:14:38 -06:00
parent 18bb7b961b
commit 73f36ab3c0
14 changed files with 568 additions and 534 deletions

View File

@ -2,13 +2,18 @@ const neutrino = require('neutrino');
const R = require('../bootstrap/require'); const R = require('../bootstrap/require');
const {targetNeutrino} = require('../server/commands'); const {targetNeutrino} = require('../server/commands');
const D = require('../debug');
const {default: Flecks} = require('../server/flecks'); const {default: Flecks} = require('../server/flecks');
const debug = D('@flecks/core/.eslintrc.js');
const { const {
FLECKS_CORE_BUILD_TARGET = 'fleck', FLECKS_CORE_BUILD_TARGET = 'fleck',
} = process.env; } = process.env;
debug('bootstrapping flecks...');
const flecks = Flecks.bootstrap(); const flecks = Flecks.bootstrap();
debug('bootstrapped');
const config = R(process.env[targetNeutrino(FLECKS_CORE_BUILD_TARGET)]); const config = R(process.env[targetNeutrino(FLECKS_CORE_BUILD_TARGET)]);
flecks.invokeFlat('@flecks/core/build', FLECKS_CORE_BUILD_TARGET, config); flecks.invokeFlat('@flecks/core/build', FLECKS_CORE_BUILD_TARGET, config);

View File

@ -29,9 +29,11 @@ const buildList = FLECKS_CORE_BUILD_LIST
.map((name) => name.trim()) .map((name) => name.trim())
.filter((e) => e); .filter((e) => e);
const flecks = Flecks.bootstrap(); export default (async () => {
debug('bootstrapping flecks...');
const flecks = Flecks.bootstrap();
debug('bootstrapped');
const buildConfigs = async () => {
debug('gathering configs'); debug('gathering configs');
let targets = flatten(flecks.invokeFlat('@flecks/core/targets')); let targets = flatten(flecks.invokeFlat('@flecks/core/targets'));
if (buildList.length > 0) { if (buildList.length > 0) {
@ -68,6 +70,4 @@ const buildConfigs = async () => {
await new Promise(() => {}); await new Promise(() => {});
} }
return webpackConfigs; return webpackConfigs;
}; })();
export default buildConfigs();

View File

@ -79,31 +79,33 @@ else {
const program = new Command(); const program = new Command();
program.enablePositionalOptions(); program.enablePositionalOptions();
// Bootstrap. // Bootstrap.
debug('bootstrapping flecks...'); (async () => {
const flecks = Flecks.bootstrap(); debug('bootstrapping flecks...');
debug('bootstrapped'); const flecks = Flecks.bootstrap();
// Register commands. debug('bootstrapped');
const commands = flecks.invokeReduce('@flecks/core/commands', undefined, undefined, program); // Register commands.
const keys = Object.keys(commands); const commands = flecks.invokeReduce('@flecks/core/commands', undefined, undefined, program);
for (let i = 0; i < keys.length; ++i) { const keys = Object.keys(commands);
const { for (let i = 0; i < keys.length; ++i) {
action, const {
args = [], action,
description, args = [],
name = keys[i], description,
options = [], name = keys[i],
} = commands[keys[i]]; options = [],
debug('adding command %s...', name); } = commands[keys[i]];
const cmd = program.command(name); debug('adding command %s...', name);
cmd.description(description); const cmd = program.command(name);
for (let i = 0; i < args.length; ++i) { cmd.description(description);
cmd.addArgument(args[i]); for (let i = 0; i < args.length; ++i) {
cmd.addArgument(args[i]);
}
for (let i = 0; i < options.length; ++i) {
cmd.option(...options[i]);
}
cmd.action(forwardProcessCode(action));
} }
for (let i = 0; i < options.length; ++i) { // Parse commandline.
cmd.option(...options[i]); program.parse(process.argv);
} })();
cmd.action(forwardProcessCode(action));
}
// Parse commandline.
program.parse(process.argv);
} }

View File

@ -1,11 +1,11 @@
import D from 'debug'; const D = require('debug');
const { const {
VSCODE_INSPECTOR_OPTIONS, VSCODE_INSPECTOR_OPTIONS,
} = process.env; } = process.env;
let hasInitialized; let hasInitialized;
export default (name) => { module.exports = (name) => {
if (!hasInitialized) { if (!hasInitialized) {
// VSCode has a problem showing colors when formatting objects. // VSCode has a problem showing colors when formatting objects.
if (VSCODE_INSPECTOR_OPTIONS) { if (VSCODE_INSPECTOR_OPTIONS) {

View File

@ -5,41 +5,47 @@ const {join} = require('path');
const banner = require('@neutrinojs/banner'); const banner = require('@neutrinojs/banner');
const copy = require('@neutrinojs/copy'); const copy = require('@neutrinojs/copy');
module.exports = require('@flecks/fleck/server/build/fleck.neutrinorc'); module.exports = (async () => {
// eslint-disable-next-line global-require
const config = await require('@flecks/fleck/server/build/fleck.neutrinorc');
module.exports.use.push(banner({ config.use.push(banner({
banner: '#!/usr/bin/env node', banner: '#!/usr/bin/env node',
include: /^cli\.js$/, include: /^cli\.js$/,
pluginId: 'shebang', pluginId: 'shebang',
raw: true, raw: true,
})); }));
module.exports.use.push(({config}) => { config.use.push(({config}) => {
config config
.plugin('executable') .plugin('executable')
.use(class Executable { .use(class Executable {
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
apply(compiler) { apply(compiler) {
compiler.hooks.afterEmit.tapAsync( compiler.hooks.afterEmit.tapAsync(
'Executable', 'Executable',
(compilation, callback) => { (compilation, callback) => {
chmod(join(__dirname, '..', 'dist', 'cli.js'), 0o755, callback); chmod(join(__dirname, '..', 'dist', 'cli.js'), 0o755, callback);
}, },
); );
} }
}); });
}); });
module.exports.use.push( config.use.push(
copy({ copy({
copyUnmodified: true, copyUnmodified: true,
patterns: [ patterns: [
{ {
from: 'template', from: 'template',
to: 'template', to: 'template',
}, },
], ],
}), }),
); );
return config;
})();

View File

@ -5,41 +5,47 @@ const {join} = require('path');
const banner = require('@neutrinojs/banner'); const banner = require('@neutrinojs/banner');
const copy = require('@neutrinojs/copy'); const copy = require('@neutrinojs/copy');
module.exports = require('@flecks/fleck/server/build/fleck.neutrinorc'); module.exports = (async () => {
// eslint-disable-next-line global-require
const config = await require('@flecks/fleck/server/build/fleck.neutrinorc');
module.exports.use.push(banner({ config.use.push(banner({
banner: '#!/usr/bin/env node', banner: '#!/usr/bin/env node',
include: /^cli\.js$/, include: /^cli\.js$/,
pluginId: 'shebang', pluginId: 'shebang',
raw: true, raw: true,
})); }));
module.exports.use.push(({config}) => { config.use.push(({config}) => {
config config
.plugin('executable') .plugin('executable')
.use(class Executable { .use(class Executable {
// eslint-disable-next-line class-methods-use-this // eslint-disable-next-line class-methods-use-this
apply(compiler) { apply(compiler) {
compiler.hooks.afterEmit.tapAsync( compiler.hooks.afterEmit.tapAsync(
'Executable', 'Executable',
(compilation, callback) => { (compilation, callback) => {
chmod(join(__dirname, '..', 'dist', 'cli.js'), 0o755, callback); chmod(join(__dirname, '..', 'dist', 'cli.js'), 0o755, callback);
}, },
); );
} }
}); });
}); });
module.exports.use.push( config.use.push(
copy({ copy({
copyUnmodified: true, copyUnmodified: true,
patterns: [ patterns: [
{ {
from: 'template', from: 'template',
to: 'template', to: 'template',
}, },
], ],
}), }),
); );
return config;
})();

View File

@ -1,4 +1,4 @@
import {execSync, spawn} from 'child_process'; import {exec, spawn} from 'child_process';
import {mkdir} from 'fs/promises'; import {mkdir} from 'fs/promises';
import {tmpdir} from 'os'; import {tmpdir} from 'os';
import {join} from 'path'; import {join} from 'path';
@ -7,23 +7,25 @@ import {D} from '@flecks/core';
const debug = D('@flecks/docker/container'); const debug = D('@flecks/docker/container');
const containerIsRunning = (name) => { const containerIsRunning = async (name) => (
try { new Promise((r, e) => {
const output = execSync( exec(
`docker container inspect -f '{{.State.Running}}' ${name}`, `docker container inspect -f '{{.State.Running}}' ${name}`,
{stdio: 'pipe'}, {stdio: 'pipe'},
).toString(); (error, stdout) => {
if ('true\n' === output) { if (error) {
return true; if (1 !== e.status) {
} e(error);
} }
catch (e) { else {
if (1 !== e.status) { r(false);
throw e; }
} }
} r('true\n' === stdout);
return false; },
}; );
})
);
export default async (flecks, key, config) => { export default async (flecks, key, config) => {
const {id} = flecks.get('@flecks/core'); const {id} = flecks.get('@flecks/core');

View File

@ -12,52 +12,54 @@ const {
const debug = D('@flecks/fleck/fleck.neutrino.js'); const debug = D('@flecks/fleck/fleck.neutrino.js');
debug('bootstrapping flecks...');
const flecks = Flecks.bootstrap();
debug('bootstrapped');
const config = require('../../../../core/src/bootstrap/fleck.neutrinorc'); const config = require('../../../../core/src/bootstrap/fleck.neutrinorc');
const compiler = flecks.invokeFleck( module.exports = (async () => {
'@flecks/fleck/compiler', debug('bootstrapping flecks...');
flecks.get('@flecks/fleck.compiler'), const flecks = Flecks.bootstrap();
); debug('bootstrapped');
if (compiler) {
config.use.unshift(compiler); const compiler = flecks.invokeFleck(
} '@flecks/fleck/compiler',
else { flecks.get('@flecks/fleck.compiler'),
config.use.unshift((neutrino) => { );
neutrino.config.plugins.delete('start-server'); if (compiler) {
config.use.unshift(compiler);
}
else {
config.use.unshift((neutrino) => {
neutrino.config.plugins.delete('start-server');
});
const configFile = flecks.localConfig('babel.config.js', '@flecks/core');
config.use.unshift(node({
babel: {configFile},
clean: {
cleanStaleWebpackAssets: false,
},
}));
}
// Augment the compiler with babel config from flecksrc.
config.use.push((neutrino) => {
const rcBabel = flecks.babel();
debug('.flecksrc: babel: %O', rcBabel);
neutrino.config.module
.rule('compile')
.use('babel')
.tap((options) => babelmerge(options, ...rcBabel.map(([, babel]) => babel)));
}); });
const configFile = flecks.localConfig('babel.config.js', '@flecks/core');
config.use.unshift(node({
babel: {configFile},
clean: {
cleanStaleWebpackAssets: false,
},
}));
}
// Augment the compiler with babel config from flecksrc. config.use.push((neutrino) => {
config.use.push((neutrino) => { // Test entrypoint.
const rcBabel = flecks.babel(); const testPaths = glob.sync(join(FLECKS_CORE_ROOT, 'test/*.js'));
debug('.flecksrc: babel: %O', rcBabel); for (let i = 0; i < flecks.platforms.length; ++i) {
neutrino.config.module testPaths.push(...glob.sync(join(FLECKS_CORE_ROOT, `test/platforms/${flecks.platforms[i]}/*.js`)));
.rule('compile') }
.use('babel') if (testPaths.length > 0) {
.tap((options) => babelmerge(options, ...rcBabel.map(([, babel]) => babel))); const testEntry = neutrino.config.entry('test').clear();
}); testPaths.forEach((path) => testEntry.add(path));
}
});
config.use.push((neutrino) => { return config;
// Test entrypoint. })();
const testPaths = glob.sync(join(FLECKS_CORE_ROOT, 'test/*.js'));
for (let i = 0; i < flecks.platforms.length; ++i) {
testPaths.push(...glob.sync(join(FLECKS_CORE_ROOT, `test/platforms/${flecks.platforms[i]}/*.js`)));
}
if (testPaths.length > 0) {
const testEntry = neutrino.config.entry('test').clear();
testPaths.forEach((path) => testEntry.add(path));
}
});
module.exports = config;

View File

@ -1,22 +1,22 @@
/* eslint-disable import/no-extraneous-dependencies */ // eslint-disable-next-line import/no-extraneous-dependencies
const config = require('@flecks/fleck/server/build/fleck.neutrinorc');
const copy = require('@neutrinojs/copy'); const copy = require('@neutrinojs/copy');
/* eslint-enable import/no-extraneous-dependencies */
config.use.push(({config}) => { module.exports = (async () => {
config.entryPoints.delete('build/template'); // eslint-disable-next-line import/no-extraneous-dependencies, global-require
}); const config = await require('@flecks/fleck/server/build/fleck.neutrinorc');
config.use.push(({config}) => {
config.use.push( config.entryPoints.delete('build/template');
copy({ });
copyUnmodified: true, config.use.push(
patterns: [ copy({
{ copyUnmodified: true,
from: 'src/build/template.ejs', patterns: [
to: 'build/template.ejs', {
}, from: 'src/build/template.ejs',
], to: 'build/template.ejs',
}), },
); ],
}),
module.exports = config; );
return config;
})();

View File

@ -14,59 +14,59 @@ const {
const debug = D('@flecks/http/http.neutrino.js'); const debug = D('@flecks/http/http.neutrino.js');
debug('bootstrapping flecks...'); module.exports = (async () => {
const flecks = Flecks.bootstrap(); debug('bootstrapping flecks...');
debug('bootstrapped'); const flecks = Flecks.bootstrap();
debug('bootstrapped');
// Neutrino configuration. // Neutrino configuration.
const config = { const config = {
options: { options: {
output: 'dist', output: 'dist',
root: FLECKS_CORE_ROOT, root: FLECKS_CORE_ROOT,
},
use: [
({config}) => {
config
.plugin('environment')
.use(EnvironmentPlugin, [{
FLECKS_CORE_BUILD_TARGET: 'client',
}]);
}, },
targets(flecks), use: [
], ({config}) => {
}; config
// Compile code. .plugin('environment')
const compiler = flecks.invokeFleck( .use(EnvironmentPlugin, [{
'@flecks/http/server/compiler', FLECKS_CORE_BUILD_TARGET: 'client',
flecks.get('@flecks/http/server.compiler'), }]);
); },
if (compiler) { await targets(flecks),
config.use.push(compiler); ],
} };
else { // Compile code.
// Use neutrino's web middleware by default. const compiler = flecks.invokeFleck(
config.use.push(web({ '@flecks/http/server/compiler',
clean: false, flecks.get('@flecks/http/server.compiler'),
hot: false, );
html: { if (compiler) {
inject: false, config.use.push(compiler);
template: flecks.localConfig('template.ejs', '@flecks/http'), }
}, else {
style: { // Use neutrino's web middleware by default.
extract: { config.use.push(web({
enabled: false, clean: false,
hot: false,
html: {
inject: false,
template: flecks.localConfig('template.ejs', '@flecks/http'),
}, },
style: { style: {
injectType: 'lazyStyleTag', extract: {
enabled: false,
},
style: {
injectType: 'lazyStyleTag',
},
}, },
}, }));
})); }
} // Configure dev server.
// Configure dev server. config.use.push(devServer(flecks));
config.use.push(devServer(flecks)); // Build the client runtime.
// Build the client runtime. config.use.push(await runtime(flecks));
config.use.push(runtime(flecks)); // Output configuration.
// Output configuration. config.use.push(outputs());
config.use.push(outputs()); return config;
})();
module.exports = config;

View File

@ -1,4 +1,4 @@
const {realpathSync} = require('fs'); const {realpath} = require('fs/promises');
const { const {
dirname, dirname,
join, join,
@ -10,116 +10,119 @@ const glob = require('glob');
const debug = D('@flecks/http/runtime'); const debug = D('@flecks/http/runtime');
module.exports = (flecks) => (neutrino) => { module.exports = async (flecks) => {
debug('bootstrapping flecks...'); debug('bootstrapping flecks...');
const httpFlecks = Flecks.bootstrap({platforms: ['client'], without: ['server']}); const httpFlecks = Flecks.bootstrap({platforms: ['client'], without: ['server']});
debug('bootstrapped'); debug('bootstrapped');
const {resolver} = httpFlecks; const runtime = await realpath(R.resolve(join(flecks.resolve('@flecks/http'), 'runtime')));
const paths = Object.entries(resolver); const fullresolve = (fleck, path) => realpath(R.resolve(join(flecks.resolve(fleck), path)));
const source = [ const entry = await fullresolve('@flecks/http', 'entry');
'module.exports = (update) => (async () => ({', const importLoader = await fullresolve('@flecks/http', 'import-loader');
" config: window[Symbol.for('@flecks/http/config')],", const tests = await realpath(R.resolve(join(flecks.resolve('@flecks/http'), 'tests')));
' flecks: Object.fromEntries(await Promise.all([', return (neutrino) => {
paths const {resolver} = httpFlecks;
.map(([path]) => [ const paths = Object.entries(resolver);
' [', const source = [
` '${path}',`, 'module.exports = (update) => (async () => ({',
` import('${path}').then((M) => (update(${paths.length}, '${path}'), M)),`, " config: window[Symbol.for('@flecks/http/config')],",
' ]', ' flecks: Object.fromEntries(await Promise.all([',
].join('\n')) paths
.join(',\n'), .map(([path]) => [
' ].map(async ([path, M]) => [path, await M]))),', ' [',
" platforms: ['client'],", ` '${path}',`,
'}))();', ` import('${path}').then((M) => (update(${paths.length}, '${path}'), M)),`,
'', ' ]',
]; ].join('\n'))
// HMR. .join(',\n'),
source.push('if (module.hot) {'); ' ].map(async ([path, M]) => [path, await M]))),',
paths.forEach(([path]) => { " platforms: ['client'],",
source.push(` module.hot.accept('${path}', () => {`); '}))();',
source.push(` window.flecks.refresh('${path}', require('${path}'));`); '',
source.push(` window.flecks.invoke('@flecks/core/hmr', '${path}');`); ];
source.push(' });'); // HMR.
}); source.push('if (module.hot) {');
source.push('}'); paths.forEach(([path]) => {
source.push(''); source.push(` module.hot.accept('${path}', async () => {`);
// Create runtime. source.push(` window.flecks.refresh('${path}', require('${path}'));`);
const runtime = realpathSync(R.resolve(join(flecks.resolve('@flecks/http'), 'runtime'))); source.push(` window.flecks.invoke('@flecks/core/hmr', '${path}');`);
neutrino.config.module source.push(' });');
.rule(runtime)
.test(runtime)
.use('runtime/http')
.loader(runtime)
.options({
source: source.join('\n'),
}); });
neutrino.config.resolve.alias source.push('}');
.set('@flecks/http/runtime$', runtime); source.push('');
flecks.runtimeCompiler('http', neutrino); // Create runtime.
// Handle runtime import. neutrino.config.module
const fullresolve = (fleck, path) => realpathSync(R.resolve(join(flecks.resolve(fleck), path))); .rule(runtime)
const entry = fullresolve('@flecks/http', 'entry'); .test(runtime)
neutrino.config.module .use('runtime/http')
.rule(entry) .loader(runtime)
.test(entry) .options({
.use('entry/http') source: source.join('\n'),
.loader(fullresolve('@flecks/http', 'import-loader'));
// Aliases.
const aliases = flecks.aliases();
if (Object.keys(aliases).length > 0) {
Object.entries(aliases)
.forEach(([from, to]) => {
neutrino.config.resolve.alias
.set(from, to);
}); });
} neutrino.config.resolve.alias
// Tests. .set('@flecks/http/runtime$', runtime);
const testRoots = Array.from(new Set( flecks.runtimeCompiler('http', neutrino);
Object.keys(httpFlecks.resolver) // Handle runtime import.
.map((fleck) => [fleck, httpFlecks.root(fleck)]), neutrino.config.module
)) .rule(entry)
.map(([fleck, root]) => ( .test(entry)
[fleck, dirname(R.resolve(join(root, 'package.json')))] .use('entry/http')
)); .loader(importLoader);
const testPaths = []; // Aliases.
testRoots.forEach(([fleck, root]) => { const aliases = flecks.aliases();
testPaths.push(...( if (Object.keys(aliases).length > 0) {
glob.sync(join(root, 'test/*.js')) Object.entries(aliases)
.map((path) => [fleck, path]) .forEach(([from, to]) => {
)); neutrino.config.resolve.alias
for (let i = 0; i < httpFlecks.platforms.length; ++i) { .set(from, to);
testPaths.push( });
...(
glob.sync(join(root, `test/platforms/${httpFlecks.platforms[i]}/*.js`))
.map((path) => [fleck, path])
),
);
} }
}); // Tests.
// Test entrypoint. const testRoots = Array.from(new Set(
if (testPaths.length > 0) { Object.keys(httpFlecks.resolver)
const testEntry = neutrino.config.entry('test').clear(); .map((fleck) => [fleck, httpFlecks.root(fleck)]),
testPaths.forEach(([, path]) => testEntry.add(path)); ))
} .map(([fleck, root]) => (
const tests = realpathSync(R.resolve(join(flecks.resolve('@flecks/http'), 'tests'))); [fleck, dirname(R.resolve(join(root, 'package.json')))]
neutrino.config.module ));
.rule(tests) const testPaths = [];
.test(tests) testRoots.forEach(([fleck, root]) => {
.use('runtime/test') testPaths.push(...(
.loader(runtime) glob.sync(join(root, 'test/*.js'))
.options({ .map((path) => [fleck, path])
source: Object.entries( ));
testPaths for (let i = 0; i < httpFlecks.platforms.length; ++i) {
.reduce( testPaths.push(
(r, [fleck, path]) => ({ ...(
...r, glob.sync(join(root, `test/platforms/${httpFlecks.platforms[i]}/*.js`))
[fleck]: [...(r[fleck] || []), `require('${path}');`], .map((path) => [fleck, path])
}),
{},
), ),
) );
.map( }
([original, paths]) => `describe('${original}', () => { ${paths.join(' ')} });`,
).join(''),
}); });
// Test entrypoint.
if (testPaths.length > 0) {
const testEntry = neutrino.config.entry('test').clear();
testPaths.forEach(([, path]) => testEntry.add(path));
}
neutrino.config.module
.rule(tests)
.test(tests)
.use('runtime/test')
.loader(runtime)
.options({
source: Object.entries(
testPaths
.reduce(
(r, [fleck, path]) => ({
...r,
[fleck]: [...(r[fleck] || []), `require('${path}');`],
}),
{},
),
)
.map(
([original, paths]) => `describe('${original}', () => { ${paths.join(' ')} });`,
).join(''),
});
};
}; };

View File

@ -1,6 +1,6 @@
/* eslint-disable no-param-reassign */ /* eslint-disable no-param-reassign */
const {dirname, join} = require('path'); const {dirname, join} = require('path');
const {realpathSync} = require('fs'); const {realpath} = require('fs/promises');
const {require: R} = require('@flecks/core/server'); const {require: R} = require('@flecks/core/server');
@ -8,19 +8,22 @@ const {
FLECKS_CORE_ROOT = process.cwd(), FLECKS_CORE_ROOT = process.cwd(),
} = process.env; } = process.env;
module.exports = (flecks) => (neutrino) => { module.exports = async (flecks) => {
const {options} = neutrino; const root = await realpath(dirname(R.resolve(join(flecks.resolve('@flecks/http'), 'entry.js'))));
const {output: originalOutput} = options; return (neutrino) => {
neutrino.config.resolve.modules.merge([ const {options} = neutrino;
join(FLECKS_CORE_ROOT, 'node_modules'), const {output: originalOutput} = options;
'node_modules', neutrino.config.resolve.modules.merge([
]); join(FLECKS_CORE_ROOT, 'node_modules'),
options.root = realpathSync(dirname(R.resolve(join(flecks.resolve('@flecks/http'), 'entry.js')))); 'node_modules',
options.source = '.'; ]);
options.mains.index = 'entry'; options.root = root;
options.mains.tests = { options.source = '.';
entry: './client/tests', options.mains.index = 'entry';
title: 'Testbed', options.mains.tests = {
entry: './client/tests',
title: 'Testbed',
};
options.output = join(originalOutput, flecks.get('@flecks/http/server.output'));
}; };
options.output = join(originalOutput, flecks.get('@flecks/http/server.output'));
}; };

View File

@ -1,79 +1,81 @@
const {realpathSync} = require('fs'); const {realpath} = require('fs/promises');
const {join} = require('path'); const {join} = require('path');
const {require: R} = require('@flecks/core/server'); const {require: R} = require('@flecks/core/server');
module.exports = (flecks) => (neutrino) => { module.exports = async (flecks) => {
const {config, resolver} = flecks; const runtime = await realpath(R.resolve(join(flecks.resolve('@flecks/server'), 'runtime')));
// Inject flecks configuration. return (neutrino) => {
const paths = Object.keys(resolver); const {config, resolver} = flecks;
const source = [ // Inject flecks configuration.
"process.env.FLECKS_CORE_BUILD_TARGET = 'server';", const paths = Object.keys(resolver);
'module.exports = (async () => ({', const source = [
` config: ${JSON.stringify(config)},`, "process.env.FLECKS_CORE_BUILD_TARGET = 'server';",
' flecks: Object.fromEntries(await Promise.all([', 'module.exports = (async () => ({',
paths.map((path) => ` ['${path}', import('${path}')]`).join(',\n'), ` config: ${JSON.stringify(config)},`,
' ].map(async ([path, M]) => [path, await M]))),', ' flecks: Object.fromEntries(await Promise.all([',
" platforms: ['server']", paths.map((path) => ` ['${path}', import('${path}')]`).join(',\n'),
'}))();', ' ].map(async ([path, M]) => [path, await M]))),',
]; " platforms: ['server']",
// HMR. '}))();',
source.push('if (module.hot) {'); ];
// Keep HMR junk out of our output path. // HMR.
source.push(' const {unlink} = require("fs/promises");'); source.push('if (module.hot) {');
source.push(' const {join} = require("path");'); // Keep HMR junk out of our output path.
source.push(' let previousHash = __webpack_hash__;'); source.push(' const {unlink} = require("fs/promises");');
source.push(' module.hot.addStatusHandler((status) => {'); source.push(' const {join} = require("path");');
source.push(' if ("idle" === status) {'); source.push(' let previousHash = __webpack_hash__;');
source.push(' require("glob")('); source.push(' module.hot.addStatusHandler((status) => {');
source.push(` join('${neutrino.options.output}', \`*\${previousHash}.hot-update.*\`),`); source.push(' if ("idle" === status) {');
source.push(' async (error, disposing) => {'); source.push(' require("glob")(');
source.push(' if (error) {'); source.push(` join('${neutrino.options.output}', \`*\${previousHash}.hot-update.*\`),`);
source.push(' throw error;'); source.push(' async (error, disposing) => {');
source.push(' return;'); source.push(' if (error) {');
source.push(' }'); source.push(' throw error;');
source.push(' await Promise.all(disposing.map(unlink));'); source.push(' return;');
source.push(' },'); source.push(' }');
source.push(' );'); source.push(' await Promise.all(disposing.map(unlink));');
source.push(' previousHash = __webpack_hash__;'); source.push(' },');
source.push(' }'); source.push(' );');
source.push(' });'); source.push(' previousHash = __webpack_hash__;');
// Hooks for each fleck. source.push(' }');
paths.forEach((path) => {
source.push(` module.hot.accept('${path}', () => {`);
source.push(` global.flecks.refresh('${path}', require('${path}'));`);
source.push(` global.flecks.invoke('@flecks/core/hmr', '${path}');`);
source.push(' });'); source.push(' });');
}); // Hooks for each fleck.
source.push('}'); paths.forEach((path) => {
// Create runtime. source.push(` module.hot.accept('${path}', async () => {`);
const entries = neutrino.config.entry('index'); source.push(` global.flecks.refresh('${path}', require('${path}'));`);
const runtime = realpathSync(R.resolve(join(flecks.resolve('@flecks/server'), 'runtime'))); source.push(` global.flecks.invoke('@flecks/core/hmr', '${path}');`);
neutrino.config.module source.push(' });');
.rule(runtime)
.test(runtime)
.use('runtime')
.loader(runtime)
.options({
source: source.join('\n'),
}); });
const allowlist = [ source.push('}');
'@flecks/server/entry', // Create runtime.
'@flecks/server/runtime', const entries = neutrino.config.entry('index');
/^@babel\/runtime\/helpers\/esm/, neutrino.config.module
]; .rule(runtime)
neutrino.config.resolve.alias .test(runtime)
.set('@flecks/server/runtime$', runtime); .use('runtime')
flecks.runtimeCompiler('server', neutrino, allowlist); .loader(runtime)
// Rewrite to signals for HMR. .options({
if ('production' !== neutrino.config.get('mode')) { source: source.join('\n'),
allowlist.push(/^webpack/); });
if (entries.has(`${R.resolve('webpack/hot/poll')}?1000`)) { const allowlist = [
entries.delete(`${R.resolve('webpack/hot/poll')}?1000`); '@flecks/server/entry',
entries.add('webpack/hot/signal'); '@flecks/server/runtime',
/^@babel\/runtime\/helpers\/esm/,
];
neutrino.config.resolve.alias
.set('@flecks/server/runtime$', runtime);
flecks.runtimeCompiler('server', neutrino, allowlist);
// Rewrite to signals for HMR.
if ('production' !== neutrino.config.get('mode')) {
allowlist.push(/^webpack/);
if (entries.has(`${R.resolve('webpack/hot/poll')}?1000`)) {
entries.delete(`${R.resolve('webpack/hot/poll')}?1000`);
entries.add('webpack/hot/signal');
}
} }
} // Externalize the rest.
// Externalize the rest. const nodeExternals = R('webpack-node-externals');
const nodeExternals = R('webpack-node-externals'); neutrino.config.externals(nodeExternals({allowlist}));
neutrino.config.externals(nodeExternals({allowlist})); };
}; };

View File

@ -14,121 +14,124 @@ const {
const debug = D('@flecks/server/server.neutrino.js'); const debug = D('@flecks/server/server.neutrino.js');
debug('bootstrapping flecks...'); module.exports = (async () => {
const flecks = Flecks.bootstrap();
debug('bootstrapped');
const { debug('bootstrapping flecks...');
hot, const flecks = Flecks.bootstrap();
inspect, debug('bootstrapped');
profile,
start: isStarting,
} = flecks.get('@flecks/server');
const entry = (neutrino) => { const {
const entries = neutrino.config.entry('index');
entries.delete(join(FLECKS_CORE_ROOT, 'src', 'index'));
entries.add('@flecks/server/entry');
};
// Augment the application-starting configuration.
const start = (neutrino) => {
if (isStarting) {
neutrino.use(startServer({name: 'index.js'}));
}
if (!neutrino.config.plugins.has('start-server')) {
return;
}
neutrino.config
.plugin('start-server')
.tap((args) => {
const options = args[0];
options.keyboard = false;
// HMR.
options.signal = !!hot;
// Debugging.
if (inspect) {
options.nodeArgs.push('--inspect');
}
// Profiling.
if (profile) {
options.nodeArgs.push('--prof');
}
// Bail hard on unhandled rejections and report.
options.nodeArgs.push('--unhandled-rejections=strict');
options.nodeArgs.push('--trace-uncaught');
return args;
});
};
const compiler = flecks.invokeFleck(
'@flecks/server/compiler',
flecks.get('@flecks/server.compiler'),
);
const config = {
options: {
output: 'dist',
root: FLECKS_CORE_ROOT,
},
use: [
entry,
start,
],
};
if (compiler) {
config.use.unshift(compiler);
}
else {
config.use.unshift((neutrino) => {
// Default to not starting application on build.
neutrino.config.plugins.delete('start-server');
});
config.use.unshift(node({
clean: false,
hot, hot,
})); inspect,
} profile,
// Stub out non-server-friendly modules on the server. start: isStarting,
const stubs = flecks.stubs(); } = flecks.get('@flecks/server');
if (stubs.length > 0) {
config.use.unshift(({config}) => { const entry = (neutrino) => {
stubs.forEach((path) => { const entries = neutrino.config.entry('index');
config.resolve.alias entries.delete(join(FLECKS_CORE_ROOT, 'src', 'index'));
.set(path, '@flecks/core/empty'); entries.add('@flecks/server/entry');
};
// Augment the application-starting configuration.
const start = (neutrino) => {
if (isStarting) {
neutrino.use(startServer({name: 'index.js'}));
}
if (!neutrino.config.plugins.has('start-server')) {
return;
}
neutrino.config
.plugin('start-server')
.tap((args) => {
const options = args[0];
options.keyboard = false;
// HMR.
options.signal = !!hot;
// Debugging.
if (inspect) {
options.nodeArgs.push('--inspect');
}
// Profiling.
if (profile) {
options.nodeArgs.push('--prof');
}
// Bail hard on unhandled rejections and report.
options.nodeArgs.push('--unhandled-rejections=strict');
options.nodeArgs.push('--trace-uncaught');
return args;
});
};
const compiler = flecks.invokeFleck(
'@flecks/server/compiler',
flecks.get('@flecks/server.compiler'),
);
const config = {
options: {
output: 'dist',
root: FLECKS_CORE_ROOT,
},
use: [
entry,
start,
],
};
if (compiler) {
config.use.unshift(compiler);
}
else {
config.use.unshift((neutrino) => {
// Default to not starting application on build.
neutrino.config.plugins.delete('start-server');
}); });
config.use.unshift(node({
clean: false,
hot,
}));
}
// Stub out non-server-friendly modules on the server.
const stubs = flecks.stubs();
if (stubs.length > 0) {
config.use.unshift(({config}) => {
stubs.forEach((path) => {
config.resolve.alias
.set(path, '@flecks/core/empty');
});
});
}
// Hardcore hax for module aliasing.
const aliases = flecks.aliases();
if (Object.keys(aliases).length > 0) {
const code = [
`const aliases = ${JSON.stringify(aliases)};`,
'const {Module} = require("module");',
'const {require: Mr} = Module.prototype;',
'Module.prototype.require = function hackedRequire(request, options) {',
' if (aliases[request]) {',
' return Mr.call(this, aliases[request], options);',
' }',
' return Mr.call(this, request, options);',
'};',
].join('\n');
config.use.push(banner({
banner: code,
pluginId: 'aliases-banner',
}));
}
// Build the server runtime.
config.use.push(await runtime(flecks));
// Give the resolver a helping hand.
config.use.push((neutrino) => {
neutrino.config.resolve.modules.merge([
join(FLECKS_CORE_ROOT, 'node_modules'),
'node_modules',
]);
}); });
}
// Hardcore hax for module aliasing.
const aliases = flecks.aliases();
if (Object.keys(aliases).length > 0) {
const code = [
`const aliases = ${JSON.stringify(aliases)};`,
'const {Module} = require("module");',
'const {require: Mr} = Module.prototype;',
'Module.prototype.require = function hackedRequire(request, options) {',
' if (aliases[request]) {',
' return Mr.call(this, aliases[request], options);',
' }',
' return Mr.call(this, request, options);',
'};',
].join('\n');
config.use.push(banner({
banner: code,
pluginId: 'aliases-banner',
}));
}
// Build the server runtime. return config;
config.use.push(runtime(flecks)); })();
// Give the resolver a helping hand.
config.use.push((neutrino) => {
neutrino.config.resolve.modules.merge([
join(FLECKS_CORE_ROOT, 'node_modules'),
'node_modules',
]);
});
module.exports = config;