refactor: build + dll

This commit is contained in:
cha0s 2022-03-18 04:18:16 -05:00
parent fa092bd512
commit 0f8d6c0551
11 changed files with 242 additions and 63 deletions

View File

@ -1,5 +1,5 @@
/* eslint-disable import/first */
require('source-map-support/register');
import 'source-map-support/register';
if ('production' !== process.env.NODE_ENV) {
try {

View File

@ -8,6 +8,7 @@ module.exports = async (flecks) => {
const config = await require('@flecks/fleck/server/build/fleck.neutrinorc')(flecks);
config.use.push(({config}) => {
config.entryPoints.delete('server/build/template');
config.entryPoints.delete('server/build/tests');
config.externals(nodeExternals({
allowlist: ['mocha/mocha.css'],
importType: 'umd',
@ -29,6 +30,10 @@ module.exports = async (flecks) => {
from: 'src/server/build/template.ejs',
to: 'server/build/template.ejs',
},
{
from: 'src/server/build/tests.js',
to: 'server/build/tests.js',
},
],
}),
);

View File

@ -19,8 +19,6 @@
},
"files": [
"build",
"client/tests.js",
"client/tests.js.map",
"entry.js",
"entry.js.map",
"import-loader.js",
@ -34,6 +32,10 @@
"server/build/template.ejs",
"server/build/http.neutrinorc.js",
"server/build/http.neutrinorc.js.map",
"server/build/http-vendor.neutrinorc.js",
"server/build/http-vendor.neutrinorc.js.map",
"server/build/tests.js",
"server/build/tests.js.map",
"src",
"tests.js",
"tests.js.map"
@ -48,7 +50,9 @@
"@neutrinojs/html-template": "^9.5.0",
"@neutrinojs/image-loader": "^9.5.0",
"@neutrinojs/style-loader": "^9.5.0",
"add-asset-html-webpack-plugin": "^5.0.1",
"autoprefixer": "^9.8.6",
"before-build-webpack": "^0.2.12",
"compression": "^1.7.4",
"express": "^4.17.1",
"glob": "^7.2.0",

View File

@ -1,13 +0,0 @@
const mochaDiv = window.document.createElement('div');
mochaDiv.id = 'mocha';
window.document.body.appendChild(mochaDiv);
require('mocha/mocha.css').use();
const mocha = require('mocha/mocha');
mocha.setup('bdd');
// eslint-disable-next-line import/no-unresolved
__non_webpack_require__('@flecks/http/tests');
mocha.run();

View File

@ -0,0 +1,76 @@
const {join} = require('path');
const {require: R} = require('@flecks/core/server');
const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
module.exports = async (flecks) => {
const config = {
options: {
output: join(
FLECKS_CORE_ROOT,
'node_modules',
'.cache',
'flecks',
),
root: FLECKS_CORE_ROOT,
},
use: [
({config, options}) => {
const dll = flecks.get('@flecks/http/server.dll');
if (dll.length > 0) {
const isProduction = 'production' === config.get('mode');
// Build the library and manifest.
config.context(options.root);
const entries = config.entry('index').clear();
dll.forEach((module) => {
entries.add(module);
});
config
.plugin('dll')
.use(
R.resolve('webpack/lib/DllPlugin'),
[
{
context: options.root,
path: join(options.output, 'http-vendor.manifest.json'),
name: 'flecks_http_vendor',
},
],
);
// Output.
config
.devtool(isProduction ? 'source-map' : 'cheap-module-source-map');
config.output
.path(options.output)
.library('flecks_http_vendor')
.filename('http-vendor.js');
config.node
.set('fs', 'empty');
// Resolution.
config.resolve.extensions
.merge([
'.wasm',
...options.extensions.map((ext) => `.${ext}`),
'.json',
]);
config.module
.rule('mjs')
.test(/\.mjs$/)
.include
.add(/node_modules/)
.end()
.type('javascript/auto');
config.resolve.modules
.merge([join(FLECKS_CORE_ROOT, 'node_modules')]);
// Reporting.
config.stats(flecks.get('@flecks/http/server.stats'));
}
},
],
};
return config;
};

View File

@ -10,6 +10,7 @@ const {EnvironmentPlugin} = require('webpack');
const devServer = require('./dev-server');
const runtime = require('./runtime');
const WaitForManifestPlugin = require('./wait-for-manifest');
const {
FLECKS_CORE_ROOT = process.cwd(),
@ -34,7 +35,7 @@ module.exports = async (flecks) => {
const {output: originalOutput} = options;
options.mains.index = join(root, 'entry');
options.mains.tests = {
entry: join(root, 'client', 'tests'),
entry: join(root, 'server', 'build', 'tests'),
title: 'Testbed',
};
options.output = join(originalOutput, flecks.get('@flecks/http/server.output'));
@ -111,7 +112,7 @@ module.exports = async (flecks) => {
},
})
.runtimeChunk('single');
// Outputs.
// Output.
config.output
.chunkFilename(isProduction ? 'assets/[name].[contenthash:8].js' : 'assets/[name].js')
.path(options.output)
@ -141,6 +142,40 @@ module.exports = async (flecks) => {
config
.plugin('inline-chunks')
.use(InlineChunkHtmlPlugin, [HtmlWebpackPlugin, [/^assets\/index(\.[^.]*)?\.js$/]]);
const dll = flecks.get('@flecks/http/server.dll');
if (!isProduction && dll.length > 0) {
const manifest = join(
FLECKS_CORE_ROOT,
'node_modules',
'.cache',
'flecks',
'http-vendor',
);
config
.plugin('wait-for-manifest')
.use(WaitForManifestPlugin, [`${manifest}.manifest.json`]);
config
.plugin('dll')
.use(
R.resolve('webpack/lib/DllReferencePlugin'),
[
{
context: FLECKS_CORE_ROOT,
manifest: `${manifest}.manifest.json`,
},
],
);
config
.plugin('include-dll')
.use(
R.resolve('add-asset-html-webpack-plugin'),
[
{
filepath: `${manifest}.js`,
},
],
);
}
};
};
// Neutrino configuration.

View File

@ -1,4 +1,4 @@
const {realpath, stat} = require('fs/promises');
const {readFile, realpath, stat} = require('fs/promises');
const {
dirname,
join,
@ -45,10 +45,14 @@ module.exports = async (flecks) => {
const fullresolve = (fleck, path) => realpath(R.resolve(join(httpFlecks.resolve(fleck), path)));
const entry = await fullresolve('@flecks/http', 'entry');
const importLoader = await fullresolve('@flecks/http', 'import-loader');
const tests = await realpath(R.resolve(join(httpFlecks.resolve('@flecks/http'), 'tests')));
const tests = await realpath(R.resolve(
join(httpFlecks.resolve('@flecks/http'), 'server', 'build', 'tests'),
));
const testsSource = (await readFile(tests)).toString();
return (neutrino) => {
const {config} = neutrino;
const {resolver} = httpFlecks;
const isProduction = 'production' === config.get('mode');
const paths = Object.entries(resolver);
const source = [
'module.exports = (update) => (async () => ({',
@ -111,45 +115,55 @@ module.exports = async (flecks) => {
entries.add(style);
});
// Tests.
const testPaths = [];
roots.forEach(([fleck, root]) => {
testPaths.push(...(
glob.sync(join(root, 'test/*.js'))
.map((path) => [fleck, path])
));
for (let i = 0; i < httpFlecks.platforms.length; ++i) {
testPaths.push(
...(
glob.sync(join(root, `test/platforms/${httpFlecks.platforms[i]}/*.js`))
.map((path) => [fleck, path])
),
);
}
});
// Test entrypoint.
if (testPaths.length > 0) {
const testEntry = config.entry('test').clear();
testPaths.forEach(([, path]) => testEntry.add(path));
}
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}');`],
}),
{},
if (!isProduction) {
const testPaths = [];
roots.forEach(([fleck, root]) => {
testPaths.push(...(
glob.sync(join(root, 'test/*.js'))
.map((path) => [fleck, path])
));
for (let i = 0; i < httpFlecks.platforms.length; ++i) {
testPaths.push(
...(
glob.sync(join(root, `test/platforms/${httpFlecks.platforms[i]}/*.js`))
.map((path) => [fleck, path])
),
)
.map(
([original, paths]) => `describe('${original}', () => { ${paths.join(' ')} });`,
).join(''),
);
}
});
config.module
.rule(tests)
.test(tests)
.use('runtime/test')
.loader(runtime)
.options({
source: testsSource.replace(
"await import('@flecks/http/tests');",
[
'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'),
),
});
}
};
};

View File

@ -0,0 +1,16 @@
const mochaDiv = window.document.createElement('div');
mochaDiv.id = 'mocha';
window.document.body.appendChild(mochaDiv);
(async () => {
await import('mocha/mocha.css');
const mocha = await import('mocha/mocha');
mocha.setup('bdd');
// eslint-disable-next-line import/no-extraneous-dependencies, import/no-unresolved
await import('@flecks/http/tests');
mocha.run();
})();

View File

@ -0,0 +1,31 @@
const {stat} = require('fs/promises');
const WebpackBeforeBuildPlugin = require('before-build-webpack');
class WaitForManifestPlugin extends WebpackBeforeBuildPlugin {
constructor(manifest) {
super(async (stats, callback) => {
// eslint-disable-next-line no-constant-condition
while (true) {
try {
// eslint-disable-next-line no-await-in-loop
await stat(manifest);
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve) => setTimeout(resolve, 100));
callback();
break;
}
catch (error) {
// eslint-disable-next-line no-await-in-loop
await new Promise((resolve) => setTimeout(resolve, 1000));
}
}
}, ['beforeCompile']);
}
}
module.exports = WaitForManifestPlugin;

View File

@ -68,6 +68,13 @@ export default {
delete neutrinoConfigs.http;
return;
}
// Only build vendor in dev.
if (neutrinoConfigs['http-vendor']) {
if (process.argv.find((arg) => 'production' === arg)) {
// eslint-disable-next-line no-param-reassign
delete neutrinoConfigs['http-vendor'];
}
}
// Bail if there's no http build.
if (!neutrinoConfigs.http) {
return;
@ -130,6 +137,10 @@ export default {
colors: true,
modules: false,
},
/**
* Modules to externalize using `webpack.DllPlugin`.
*/
dll: [],
/**
* Force building http target even if there's a fleck target.
*/
@ -171,7 +182,10 @@ export default {
debug('bootstrapped');
flecks.set('$flecks/http.flecks', httpFlecks);
},
'@flecks/core.targets': () => ['http'],
'@flecks/core.targets': (flecks) => [
'http',
...(flecks.get('@flecks/http/server.dll').length > 0 ? ['http-vendor'] : []),
],
'@flecks/http.routes': (flecks) => [
{
method: 'get',

View File

@ -143,10 +143,7 @@ module.exports = async (flecks) => {
// Give the resolver a helping hand.
config.use.push(({config}) => {
config.resolve.modules.merge([
join(FLECKS_CORE_ROOT, 'node_modules'),
'node_modules',
]);
config.resolve.modules.merge([join(FLECKS_CORE_ROOT, 'node_modules')]);
});
return config;