2022-03-18 04:18:16 -05:00
|
|
|
const {readFile, realpath, stat} = require('fs/promises');
|
2022-02-26 11:58:54 -06:00
|
|
|
const {
|
|
|
|
dirname,
|
|
|
|
join,
|
|
|
|
} = require('path');
|
2022-02-25 04:58:08 -06:00
|
|
|
|
2022-02-28 10:29:56 -06:00
|
|
|
const {D} = require('@flecks/core');
|
2022-02-25 04:58:08 -06:00
|
|
|
const {Flecks, require: R} = require('@flecks/core/server');
|
2022-02-26 11:58:54 -06:00
|
|
|
const glob = require('glob');
|
2022-02-25 04:58:08 -06:00
|
|
|
|
2022-03-19 16:11:39 -05:00
|
|
|
const debug = D('@flecks/web/runtime');
|
2022-02-25 04:58:08 -06:00
|
|
|
|
2022-03-01 10:14:38 -06:00
|
|
|
module.exports = async (flecks) => {
|
2022-02-25 04:58:08 -06:00
|
|
|
debug('bootstrapping flecks...');
|
2022-03-22 20:43:05 -05:00
|
|
|
const webFlecks = Flecks.bootstrap({
|
2022-03-10 14:32:51 -06:00
|
|
|
platforms: ['client', '!server'],
|
|
|
|
});
|
2022-02-25 04:58:08 -06:00
|
|
|
debug('bootstrapped');
|
2022-03-17 15:15:39 -05:00
|
|
|
const rootMap = {};
|
2022-03-22 20:43:05 -05:00
|
|
|
Object.keys(webFlecks.resolver)
|
2022-03-17 15:15:39 -05:00
|
|
|
.forEach((fleck) => {
|
2022-03-22 20:43:05 -05:00
|
|
|
rootMap[webFlecks.root(fleck)] = fleck;
|
2022-03-17 15:15:39 -05:00
|
|
|
});
|
|
|
|
const roots = Object.entries(rootMap)
|
|
|
|
.map(([root, fleck]) => (
|
|
|
|
[fleck, dirname(R.resolve(join(root, 'package.json')))]
|
|
|
|
));
|
|
|
|
const styles = (
|
|
|
|
await Promise.all(
|
|
|
|
roots
|
|
|
|
.map(async ([, path]) => {
|
|
|
|
try {
|
|
|
|
const filename = join(path, 'index.css');
|
|
|
|
await stat(filename);
|
|
|
|
return filename;
|
|
|
|
}
|
|
|
|
catch (error) {
|
|
|
|
return undefined;
|
|
|
|
}
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
)
|
|
|
|
.filter((filename) => !!filename);
|
2022-03-22 20:43:05 -05:00
|
|
|
const runtime = await realpath(R.resolve(join(webFlecks.resolve('@flecks/web'), 'runtime')));
|
2022-03-18 04:18:16 -05:00
|
|
|
const tests = await realpath(R.resolve(
|
2022-03-22 20:43:05 -05:00
|
|
|
join(webFlecks.resolve('@flecks/web'), 'server', 'build', 'tests'),
|
2022-03-18 04:18:16 -05:00
|
|
|
));
|
|
|
|
const testsSource = (await readFile(tests)).toString();
|
2022-03-01 10:14:38 -06:00
|
|
|
return (neutrino) => {
|
2022-03-12 07:01:00 -06:00
|
|
|
const {config} = neutrino;
|
2022-03-22 20:43:05 -05:00
|
|
|
const {resolver} = webFlecks;
|
2022-03-18 04:18:16 -05:00
|
|
|
const isProduction = 'production' === config.get('mode');
|
2022-03-01 10:14:38 -06:00
|
|
|
const paths = Object.entries(resolver);
|
|
|
|
const source = [
|
|
|
|
'module.exports = (update) => (async () => ({',
|
2022-03-19 16:11:39 -05:00
|
|
|
" config: window[Symbol.for('@flecks/web.config')],",
|
2022-03-01 10:14:38 -06:00
|
|
|
' flecks: Object.fromEntries(await Promise.all([',
|
|
|
|
paths
|
|
|
|
.map(([path]) => [
|
|
|
|
' [',
|
|
|
|
` '${path}',`,
|
|
|
|
` import('${path}').then((M) => (update(${paths.length}, '${path}'), M)),`,
|
|
|
|
' ]',
|
|
|
|
].join('\n'))
|
|
|
|
.join(',\n'),
|
|
|
|
' ].map(async ([path, M]) => [path, await M]))),',
|
|
|
|
" platforms: ['client'],",
|
|
|
|
'}))();',
|
|
|
|
'',
|
|
|
|
];
|
|
|
|
// HMR.
|
|
|
|
source.push('if (module.hot) {');
|
|
|
|
paths.forEach(([path]) => {
|
|
|
|
source.push(` module.hot.accept('${path}', async () => {`);
|
2022-03-06 12:48:34 -06:00
|
|
|
source.push(` const updatedFleck = require('${path}');`);
|
|
|
|
source.push(` window.flecks.refresh('${path}', updatedFleck);`);
|
2022-03-08 16:03:06 -06:00
|
|
|
source.push(` window.flecks.invoke('@flecks/core.hmr', '${path}', updatedFleck);`);
|
2022-03-01 10:14:38 -06:00
|
|
|
source.push(' });');
|
2022-02-25 04:58:08 -06:00
|
|
|
});
|
2022-03-01 10:14:38 -06:00
|
|
|
source.push('}');
|
|
|
|
source.push('');
|
|
|
|
// Create runtime.
|
2022-03-12 07:01:00 -06:00
|
|
|
config.module
|
2022-03-01 10:14:38 -06:00
|
|
|
.rule(runtime)
|
|
|
|
.test(runtime)
|
2022-03-22 20:43:05 -05:00
|
|
|
.use('runtime/web')
|
2022-03-01 10:14:38 -06:00
|
|
|
.loader(runtime)
|
|
|
|
.options({
|
|
|
|
source: source.join('\n'),
|
2022-02-25 04:58:08 -06:00
|
|
|
});
|
2022-03-12 07:01:00 -06:00
|
|
|
config.resolve.alias
|
2022-03-19 16:11:39 -05:00
|
|
|
.set('@flecks/web/runtime$', runtime);
|
2022-03-22 20:43:05 -05:00
|
|
|
flecks.runtimeCompiler(webFlecks.resolver, 'web', neutrino);
|
2022-03-01 10:14:38 -06:00
|
|
|
// Aliases.
|
2022-03-22 20:43:05 -05:00
|
|
|
const aliases = webFlecks.aliases();
|
2022-03-01 10:14:38 -06:00
|
|
|
if (Object.keys(aliases).length > 0) {
|
|
|
|
Object.entries(aliases)
|
|
|
|
.forEach(([from, to]) => {
|
2022-03-12 07:01:00 -06:00
|
|
|
config.resolve.alias
|
2022-03-01 10:14:38 -06:00
|
|
|
.set(from, to);
|
|
|
|
});
|
2022-02-26 11:58:54 -06:00
|
|
|
}
|
2022-03-17 15:15:39 -05:00
|
|
|
// Styles.
|
|
|
|
const entries = config.entry('index');
|
|
|
|
styles.forEach((style) => {
|
|
|
|
entries.add(style);
|
|
|
|
});
|
2022-03-01 10:14:38 -06:00
|
|
|
// Tests.
|
2022-03-18 04:18:16 -05:00
|
|
|
if (!isProduction) {
|
|
|
|
const testPaths = [];
|
|
|
|
roots.forEach(([fleck, root]) => {
|
|
|
|
testPaths.push(...(
|
|
|
|
glob.sync(join(root, 'test/*.js'))
|
|
|
|
.map((path) => [fleck, path])
|
|
|
|
));
|
2022-03-22 20:43:05 -05:00
|
|
|
for (let i = 0; i < webFlecks.platforms.length; ++i) {
|
2022-03-18 04:18:16 -05:00
|
|
|
testPaths.push(
|
|
|
|
...(
|
2022-03-22 20:43:05 -05:00
|
|
|
glob.sync(join(root, `test/platforms/${webFlecks.platforms[i]}/*.js`))
|
2022-03-18 04:18:16 -05:00
|
|
|
.map((path) => [fleck, path])
|
2022-03-01 10:14:38 -06:00
|
|
|
),
|
2022-03-18 04:18:16 -05:00
|
|
|
);
|
|
|
|
}
|
2022-03-01 10:14:38 -06:00
|
|
|
});
|
2022-03-18 04:18:16 -05:00
|
|
|
config.module
|
|
|
|
.rule(tests)
|
|
|
|
.test(tests)
|
|
|
|
.use('runtime/test')
|
|
|
|
.loader(runtime)
|
|
|
|
.options({
|
|
|
|
source: testsSource.replace(
|
2022-03-19 16:11:39 -05:00
|
|
|
"await import('@flecks/web/tests');",
|
2022-03-18 04:18:16 -05:00
|
|
|
[
|
|
|
|
'const tests = {};',
|
|
|
|
Object.entries(
|
|
|
|
testPaths
|
|
|
|
.reduce(
|
|
|
|
(r, [fleck, path]) => ({
|
|
|
|
...r,
|
|
|
|
[fleck]: [...(r[fleck] || []), `require('${path}');`],
|
|
|
|
}),
|
|
|
|
{},
|
|
|
|
),
|
|
|
|
)
|
|
|
|
.map(
|
|
|
|
([original, paths]) => (
|
|
|
|
[
|
|
|
|
`describe('${original}', () => {`,
|
|
|
|
` ${paths.join('\n ')}`,
|
|
|
|
'});',
|
|
|
|
].join('\n')
|
|
|
|
),
|
|
|
|
).join('\n'),
|
|
|
|
'await Promise.all(Object.values(tests));',
|
|
|
|
].join('\n'),
|
|
|
|
),
|
|
|
|
});
|
|
|
|
}
|
2022-03-01 10:14:38 -06:00
|
|
|
};
|
2022-02-25 04:58:08 -06:00
|
|
|
};
|