flecks/packages/web/build/runtime.js

152 lines
4.6 KiB
JavaScript
Raw Normal View History

2024-01-16 00:28:20 -06:00
const {access, readFile} = require('fs/promises');
2022-02-26 11:58:54 -06:00
const {
2024-01-13 06:19:49 -06:00
basename,
2022-02-26 11:58:54 -06:00
dirname,
2024-01-13 06:19:49 -06:00
extname,
2022-02-26 11:58:54 -06:00
join,
} = require('path');
2022-02-25 04:58:08 -06:00
2024-01-16 00:28:20 -06:00
const Server = require('@flecks/core/build/server');
const {glob} = require('@flecks/core/server');
2022-02-25 04:58:08 -06:00
2023-11-30 21:41:42 -06:00
module.exports = async (config, env, argv, flecks) => {
2024-01-16 00:28:20 -06:00
const buildFlecks = await Server.from({
config: flecks.config,
2022-03-10 14:32:51 -06:00
platforms: ['client', '!server'],
});
2024-01-16 00:28:20 -06:00
const {resolver, flecks: webFlecks} = buildFlecks;
const paths = Object.keys(webFlecks)
.filter((fleck) => !['@flecks/server'].includes(fleck));
2022-03-17 15:15:39 -05:00
const styles = (
await Promise.all(
2024-01-16 00:28:20 -06:00
Object.entries(flecks.roots)
.map(async ([fleck, {request}]) => {
2024-01-13 06:19:49 -06:00
// Compiled? It will be included with the compilation.
2024-01-16 00:28:20 -06:00
if (flecks.resolved[fleck]) {
2024-01-13 06:19:49 -06:00
return undefined;
2022-04-02 07:29:28 -05:00
}
2022-03-17 15:15:39 -05:00
try {
2024-01-16 00:28:20 -06:00
const fleckResolved = await resolver.resolve(fleck);
const parentResolved = dirname(await resolver.resolve(join(request, 'package.json')));
const sub = fleckResolved.slice(parentResolved.length + 1);
const style = join(parentResolved, 'assets', `${basename(sub, extname(sub))}.css`);
2024-01-13 06:19:49 -06:00
await access(style);
return style;
2022-03-17 15:15:39 -05:00
}
catch (error) {
return undefined;
}
}),
)
)
.filter((filename) => !!filename);
2024-01-16 00:28:20 -06:00
const runtime = await flecks.resolver.resolve(join('@flecks/web/runtime'));
2023-11-30 21:41:42 -06:00
const isProduction = 'production' === argv.mode;
2024-01-16 00:28:20 -06:00
const resolvedPaths = (await Promise.all(
paths.map(async (path) => [path, await flecks.resolver.resolve(path)]),
))
.filter(([, resolved]) => resolved)
.map(([path]) => path);
2023-11-30 21:41:42 -06:00
const source = [
'module.exports = (update) => (async () => ({',
" config: window[Symbol.for('@flecks/web.config')],",
' flecks: Object.fromEntries(await Promise.all([',
2024-01-16 00:28:20 -06:00
...resolvedPaths
.map((path) => [
2023-11-30 21:41:42 -06:00
' [',
` '${path}',`,
` import('${path}').then((M) => (update(${paths.length}, '${path}'), M)),`,
2024-01-16 00:28:20 -06:00
' ],',
]).flat(),
2023-11-30 21:41:42 -06:00
' ].map(async ([path, M]) => [path, await M]))),',
" platforms: ['client'],",
'}))();',
'',
];
2024-01-16 00:28:20 -06:00
// HMrequire.
2023-11-30 21:41:42 -06:00
source.push('if (module.hot) {');
2024-01-16 00:28:20 -06:00
resolvedPaths.forEach((path) => {
2023-11-30 21:41:42 -06:00
source.push(` module.hot.accept('${path}', async () => {`);
source.push(` const updatedFleck = require('${path}');`);
source.push(` window.flecks.refresh('${path}', updatedFleck);`);
source.push(` window.flecks.invoke('@flecks/core.hmr', '${path}', updatedFleck);`);
source.push(' });');
});
source.push('}');
source.push('');
// Create runtime.
config.module.rules.push({
test: runtime,
use: [
{
loader: runtime,
options: {
source: source.join('\n'),
},
},
],
});
config.resolve.alias['@flecks/web/runtime$'] = runtime;
2024-01-16 00:28:20 -06:00
// Stubs.
buildFlecks.stubs.forEach((stub) => {
config.module.rules.push(
{
test: stub,
use: 'null-loader',
},
);
});
buildFlecks.runtimeCompiler('web', config);
2023-11-30 21:41:42 -06:00
// Aliases.
2024-01-16 00:28:20 -06:00
Object.entries(buildFlecks.resolved)
.forEach(([from, to]) => {
config.resolve.alias[from] = to;
});
2023-11-30 21:41:42 -06:00
// Styles.
config.entry.index.push(...styles);
// Tests.
if (!isProduction) {
2024-01-13 06:19:49 -06:00
const testEntries = await Promise.all(
2024-01-16 00:28:20 -06:00
Object.entries(buildFlecks.roots)
.map(async ([parent, {request}]) => {
const paths = [];
const rootTests = await glob(join(request, 'test', '*.js'));
paths.push(...rootTests);
const platformTests = await Promise.all(
buildFlecks.platforms.map((platform) => (
glob(join(request, 'test', 'platforms', platform, '*.js'))
)),
);
paths.push(...platformTests.flat());
return [parent, paths];
}),
);
const tests = await resolver.resolve(
join('@flecks/web', 'server', 'build', 'tests'),
2024-01-13 06:19:49 -06:00
);
2023-11-30 21:41:42 -06:00
const testsSource = (await readFile(tests)).toString();
config.module.rules.push({
test: tests,
use: [
{
loader: runtime,
options: {
source: testsSource.replace(
2024-01-13 06:19:49 -06:00
" await import('@flecks/web/tests');",
testEntries
.filter(([, paths]) => paths.length > 0)
.map(([root, paths]) => (
[
` describe('${root}', () => {`,
` ${paths.map((path) => `require('${path}');`).join('\n ')}`,
' });',
].join('\n')
)).join('\n\n'),
2022-03-01 10:14:38 -06:00
),
2023-11-30 21:41:42 -06:00
},
},
],
});
}
2022-02-25 04:58:08 -06:00
};