refactor: build

This commit is contained in:
cha0s 2024-01-22 09:16:07 -06:00
parent 7711c7cb2d
commit 0c8ff56850
104 changed files with 651 additions and 376 deletions

View File

@ -1,3 +1,4 @@
'@flecks/build': {}
'@flecks/core':
packageManager: yarn
'@flecks/create-app': {}

119
packages/build/.gitignore vendored Normal file
View File

@ -0,0 +1,119 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# Diagnostic reports (https://nodejs.org/api/report.html)
report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
*.lcov
# nyc test coverage
.nyc_output
# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Snowpack dependency directory (https://snowpack.dev/)
web_modules/
# TypeScript cache
*.tsbuildinfo
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
.env.test
# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache
# Next.js build output
.next
out
# Nuxt.js build / generate output
.nuxt
dist
# Gatsby files
.cache/
# Comment in the public line in if your project uses Gatsby and not Next.js
# https://nextjs.org/blog/next-9-1#public-directory-support
# public
# vuepress build output
.vuepress/dist
# Serverless directories
.serverless/
# FuseBox cache
.fusebox/
# DynamoDB Local files
.dynamodb/
# TernJS port file
.tern-port
# Stores VSCode versions used for testing VSCode extensions
.vscode-test
# yarn v2
.yarn/cache
.yarn/unplugged
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
# copy-webpack-plugin charity
.git

View File

@ -0,0 +1 @@
module.exports = require('./default.eslint.config')(require('./build').from());

View File

@ -1,12 +1,11 @@
const {realpath} = require('fs/promises');
const {dirname, join} = require('path');
const D = require('@flecks/core/build/debug');
const {Flecks} = require('@flecks/core/build/flecks');
const babelmerge = require('babel-merge');
const set = require('lodash.set');
const D = require('./debug');
const explicate = require('./explicate');
const {Flecks} = require('./flecks');
const loadConfig = require('./load-config');
const Resolver = require('./resolver');
@ -14,7 +13,7 @@ const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
const debug = D('@flecks/core/build/bootstrap');
const debug = D('@flecks/build/build/build');
const debugSilly = debug.extend('silly');
function environmentalize(path) {
@ -39,11 +38,11 @@ function environmentConfiguration(config) {
.map(([subkey, value]) => [subkey.split('_'), value])
.forEach(([path, jsonOrString]) => {
try {
set(config, [fleck, ...path], JSON.parse(jsonOrString));
Flecks.set(config, [fleck, ...path], JSON.parse(jsonOrString));
debug('read (%s) as JSON', jsonOrString);
}
catch (error) {
set(config, [fleck, ...path], jsonOrString);
Flecks.set(config, [fleck, ...path], jsonOrString);
debug('read (%s) as string', jsonOrString);
}
});
@ -51,7 +50,7 @@ function environmentConfiguration(config) {
return config;
}
module.exports = class Server extends Flecks {
module.exports = class Build extends Flecks {
aliased = {};
@ -206,10 +205,6 @@ module.exports = class Server extends Flecks {
};
}
get extensions() {
return this.invokeFlat('@flecks/core.exts').flat();
}
static async from(
{
config: configParameter,
@ -247,7 +242,7 @@ module.exports = class Server extends Flecks {
}
loadBuildConfigs() {
Object.entries(this.invoke('@flecks/core.build.config'))
Object.entries(this.invoke('@flecks/build.files'))
.forEach(([fleck, configs]) => {
configs.forEach((config) => {
this.buildConfigs[config] = fleck;
@ -298,16 +293,16 @@ module.exports = class Server extends Flecks {
{
flecks,
path,
resolved,
source,
},
]) => {
flecks.forEach((fleck) => {
allowlist.push(fleck);
});
debugSilly('%s runtime de-externalized %s, alias: %s', runtime, root, resolved);
allowlist.push(new RegExp(`^${path}`));
// flecks.forEach((fleck) => {
// allowlist.push(fleck);
// });
debugSilly('%s runtime de-externalized %s, alias: %s', runtime, root, source || path);
// Alias.
config.resolve.alias[path] = source || resolved;
config.resolve.alias[path] = source || path;
// Root aliases.
if (root) {
config.resolve.alias[
@ -315,7 +310,7 @@ module.exports = class Server extends Flecks {
] = join(FLECKS_CORE_ROOT, 'node_modules');
config.resolve.fallback[path] = root;
}
includes.push(root || resolved);
includes.push(root || path);
}),
);
// Compile.
@ -347,7 +342,7 @@ module.exports = class Server extends Flecks {
}
});
// Our very own lil' chunk.
set(config, 'optimization.splitChunks.cacheGroups.flecks-compiled', {
Flecks.set(config, 'optimization.splitChunks.cacheGroups.flecks-compiled', {
chunks: 'all',
enforce: true,
priority: 100,

View File

@ -0,0 +1,12 @@
const Build = require('./build');
const configFn = require('./fleck.webpack.config');
const {ProcessAssets} = require('./process-assets');
const {executable} = require('./webpack');
module.exports = async (env, argv) => {
const flecks = await Build.from();
const config = await configFn(env, argv, flecks);
config.plugins.push(new ProcessAssets());
config.plugins.push(executable());
return config;
};

View File

@ -1,12 +1,12 @@
#!/usr/bin/env node
const D = require('@flecks/core/build/debug');
const {Command} = require('commander');
const Build = require('./build');
const {processCode} = require('./commands');
const D = require('./debug');
const Server = require('./server');
const debug = D('@flecks/core/cli');
const debug = D('@flecks/build/build/cli');
const debugSilly = debug.extend('silly');
// Asynchronous command process code forwarding.
@ -38,10 +38,10 @@ program
// Bootstrap.
(async () => {
debugSilly('bootstrapping flecks...');
const flecks = await Server.from();
const flecks = await Build.from();
debugSilly('bootstrapped');
// Register commands.
const commands = flecks.invokeMerge('@flecks/core.commands', program);
const commands = flecks.invokeMerge('@flecks/build.commands', program);
const keys = Object.keys(commands).sort();
for (let i = 0; i < keys.length; ++i) {
const {

View File

@ -1,23 +1,23 @@
const {spawn} = require('child_process');
const {join, normalize} = require('path');
const D = require('@flecks/core/build/debug');
const {Argument, Option, program} = require('commander');
const {glob} = require('glob');
const rimraf = require('rimraf');
const D = require('./debug');
const addFleckToYml = require('./add-fleck-to-yml');
const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
const debug = D('@flecks/core/commands');
const debug = D('@flecks/build/build/commands');
const debugSilly = debug.extend('silly');
const flecksRoot = normalize(FLECKS_CORE_ROOT);
exports.commands = (program, flecks) => {
const {packageManager} = flecks.get('@flecks/core');
const {packageManager} = flecks.get('@flecks/build');
const commands = {
add: {
args: [
@ -33,7 +33,7 @@ exports.commands = (program, flecks) => {
args.push(packageManager, ['install', fleck]);
}
args.push({stdio: 'inherit'});
await module.exports.processCode(spawn(...args));
await exports.processCode(spawn(...args));
await addFleckToYml(fleck);
},
},
@ -62,7 +62,8 @@ exports.commands = (program, flecks) => {
if (targets.length > 0) {
commands.build = {
args: [
new Argument('[target]', 'build target').choices(targets.map(([, target]) => target)),
program.createArgument('[target]', 'build target')
.choices(targets.map(([, target]) => target)),
],
options: [
['-d, --no-production', 'dev build'],
@ -84,7 +85,7 @@ exports.commands = (program, flecks) => {
'--mode', (production && !hot) ? 'production' : 'development',
...((watch || hot) ? ['--watch'] : []),
];
return module.exports.spawnWith(
return exports.spawnWith(
cmd,
{
env: {
@ -116,7 +117,7 @@ exports.commands = (program, flecks) => {
'.',
];
promises.push(new Promise((resolve, reject) => {
const child = module.exports.spawnWith(
const child = exports.spawnWith(
cmd,
{
cwd,

View File

@ -7,10 +7,11 @@ const {
} = require('fs');
const {join} = require('path');
const D = require('./debug');
const Server = require('./server');
const D = require('@flecks/core/build/debug');
const debug = D('@flecks/core/build/eslint.config.js');
const Build = require('./build');
const debug = D('@flecks/build/build/eslint.config.js');
const {
FLECKS_CORE_ROOT = process.cwd(),
@ -21,7 +22,7 @@ const {
if (FLECKS_CORE_SYNC_FOR_ESLINT) {
(async () => {
debug('bootstrapping flecks...');
const flecks = await Server.from();
const flecks = await Build.from();
debug('bootstrapped');
// Load and finalize ESLint configuration.
const eslintConfig = await require(
@ -64,8 +65,14 @@ else {
module.exports = parsed;
}
catch (error) {
// eslint-disable-next-line no-console
console.error(error);
if (error.message.match(/Unexpected .*? in JSON/)) {
// eslint-disable-next-line no-console
console.error('Expected JSON, got:\n%s', json);
}
else {
// eslint-disable-next-line no-console
console.error(error);
}
}
}
}

View File

@ -37,9 +37,6 @@ module.exports = async function explicate(
) {
return;
}
if (path !== request) {
resolver.addAlias(path, request);
}
descriptors[request] = descriptor;
}
async function getRootDescriptor(descriptor) {
@ -86,23 +83,35 @@ module.exports = async function explicate(
if (resolved) {
await doExplication(descriptor);
}
if (descriptor.path !== descriptor.request) {
resolver.addAlias(descriptor.path, descriptor.request);
}
await Promise.all(
platforms
.filter((platform) => !platform.startsWith('!'))
.map(async (platform) => {
if (await resolver.resolve(join(descriptor.request, platform))) {
return doExplication({
path: join(descriptor.path, platform),
request: join(descriptor.request, platform),
});
const [path, request] = [
join(descriptor.path, platform),
join(descriptor.request, platform),
];
await doExplication({path, request});
if (path !== request) {
resolver.addAlias(path, request);
}
return;
}
if (await resolver.resolve(join(descriptor.request, 'src', platform))) {
return doExplication({
path: join(descriptor.path, platform),
request: join(descriptor.request, 'src', platform),
});
const [path, request] = [
join(descriptor.path, platform),
join(descriptor.request, 'src', platform),
];
await doExplication({path, request});
if (path !== request) {
resolver.addAlias(path, request);
}
return;
}
return undefined;
}),
);
}

View File

@ -0,0 +1,59 @@
const {join} = require('path');
const webpack = require('webpack');
const {commands} = require('./commands');
const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
exports.hooks = {
'@flecks/build.extensions': () => ['.mjs', '.js', '.json', '.wasm'],
'@flecks/build.config': async (target, config, env, argv, flecks) => {
if (flecks.get('@flecks/build.profile').includes(target)) {
config.plugins.push(
new webpack.debug.ProfilingPlugin({
outputPath: join(FLECKS_CORE_ROOT, `profile.build-${target}.json`),
}),
);
}
if (Object.entries(flecks.compiled).length > 0) {
config.resolve.symlinks = false;
}
},
'@flecks/build.files': () => [
/**
* Babel configuration. See: https://babeljs.io/docs/en/config-files
*/
'babel.config.js',
/**
* ESLint defaults. The generated `eslint.config.js` just reads from this file so that the
* build can dynamically configure parts of ESLint.
*/
'default.eslint.config.js',
/**
* ESLint configuration managed by flecks to allow async.
*/
'eslint.config.js',
/**
* Flecks webpack configuration. See: https://webpack.js.org/configuration/
*/
'fleckspack.config.js',
/**
* Fleck build configuration. See: https://webpack.js.org/configuration/
*/
'fleck.webpack.config.js',
],
'@flecks/build.commands': commands,
'@flecks/core.config': () => ({
/**
* The package manager used for tasks.
*/
packageManager: 'npm',
/**
* Build targets to profile with `webpack.debug.ProfilingPlugin`.
*/
profile: [],
}),
};

View File

@ -1,9 +1,10 @@
require('source-map-support/register');
const D = require('./debug');
const Server = require('./server');
const D = require('@flecks/core/build/debug');
const debug = D('@flecks/core/build/fleckspack.config.js');
const Build = require('./build');
const debug = D('@flecks/build/build/fleckspack.config.js');
const {
FLECKS_CORE_BUILD_LIST = '',
@ -16,7 +17,7 @@ const buildList = FLECKS_CORE_BUILD_LIST
module.exports = async (env, argv) => {
debug('bootstrapping flecks...');
const flecks = await Server.from();
const flecks = await Build.from();
debug('bootstrapped');
debug('gathering configs');
const {targets} = flecks;
@ -43,11 +44,11 @@ module.exports = async (env, argv) => {
));
await Promise.all(
entries.map(async ([target, config]) => (
Promise.all(flecks.invokeFlat('@flecks/core.build', target, config, env, argv))
Promise.all(flecks.invokeFlat('@flecks/build.config', target, config, env, argv))
)),
);
const webpackConfigs = Object.fromEntries(entries);
await Promise.all(flecks.invokeFlat('@flecks/core.build.alter', webpackConfigs, env, argv));
await Promise.all(flecks.invokeFlat('@flecks/build.config.alter', webpackConfigs, env, argv));
const enterableWebpackConfigs = Object.values(webpackConfigs)
.filter((webpackConfig) => {
if (!webpackConfig.entry) {

View File

@ -1,9 +1,9 @@
const {readFile} = require('fs/promises');
const {join} = require('path');
const D = require('./debug');
const D = require('@flecks/core/build/debug');
const debug = D('@flecks/core:load-config');
const debug = D('@flecks/build/build/load-config');
const {
FLECKS_CORE_ROOT = process.cwd(),
@ -22,7 +22,11 @@ module.exports = async function loadConfig() {
throw error;
}
const {name} = require(join(FLECKS_CORE_ROOT, 'package.json'));
const barebones = {'@flecks/core': {}, '@flecks/fleck': {}};
const barebones = {
'@flecks/build': {},
'@flecks/core': {},
'@flecks/fleck': {},
};
if (barebones[name]) {
delete barebones[name];
}

View File

@ -0,0 +1,74 @@
const {join} = require('path');
const {glob} = require('glob');
const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
exports.ProcessAssets = class ProcessAssets {
constructor(flecks) {
this.flecks = flecks;
}
apply(compiler) {
compiler.hooks.thisCompilation.tap('@flecks/build.process-assets', (compilation) => {
compilation.hooks.processAssets.tapAsync(
{
name: '@flecks/build.process-assets',
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_REPORT,
},
async (assets, callback) => {
if (this.flecks) {
await this.flecks.invokeSequentialAsync(
'@flecks/build.processAssets',
assets,
compilation,
);
}
else {
await exports.hook(assets, compilation);
}
callback();
},
);
});
}
};
exports.hook = async (assets, compilation, flecks) => {
const {RawSource} = compilation.compiler.webpack.sources;
const packageJson = assets['package.json'];
const json = JSON.parse(packageJson.source().toString());
const {files} = json;
// Add defaults.
files.push('build');
// Add source if it exists.
if ((await glob(join(FLECKS_CORE_ROOT, 'src/**/*.js'))).length > 0) {
files.push('src');
}
// Add tests if they exist.
const testFiles = await glob(join(FLECKS_CORE_ROOT, 'test/**/*.js'));
if (testFiles.length > 0) {
files.push('test');
}
// Let others have a say.
if (flecks) {
await flecks.invokeSequentialAsync('@flecks/build.packageJson', json, compilation);
}
// Add any sourcemaps.
json.files = json.files
.map((filename) => {
const maybeWithMap = [filename];
if (compilation.assets[`${filename}.map`]) {
maybeWithMap.push(`${filename}.map`);
}
return maybeWithMap;
})
.flat();
// Sort and uniquify.
json.files = [...new Set(json.files.sort((l, r) => (l < r ? -1 : 1)))];
compilation.updateAsset('package.json', new RawSource(JSON.stringify(json, null, 2)));
};

View File

@ -1,13 +1,12 @@
const {join} = require('path');
const D = require('@flecks/core/build/debug');
const {CachedInputFileSystem, ResolverFactory} = require('enhanced-resolve');
const AppendPlugin = require('enhanced-resolve/lib/AppendPlugin');
const AliasPlugin = require('enhanced-resolve/lib/AliasPlugin');
const fs = require('graceful-fs');
const D = require('./debug');
const debug = D('@flecks/core/build/resolver');
const debug = D('@flecks/build/build/resolver');
const debugSilly = debug.extend('silly');
const {

View File

@ -20,7 +20,7 @@ exports.banner = (options) => (
exports.copy = (options) => (new CopyPlugin(options));
exports.defaultConfig = (flecks, specializedConfig) => {
const {extensions} = flecks;
const extensions = flecks.invokeFlat('@flecks/build.extensions').flat();
const extensionsRegex = exports.regexFromExtensions(extensions);
const defaults = {
context: FLECKS_CORE_ROOT,
@ -82,7 +82,7 @@ exports.defaultConfig = (flecks, specializedConfig) => {
};
// Include a shebang and set the executable bit..
exports.executable = () => ([
exports.executable = () => (
new class Executable {
// eslint-disable-next-line class-methods-use-this
@ -95,8 +95,8 @@ exports.executable = () => ([
);
}
}(),
]);
}()
);
exports.externals = nodeExternals;

View File

@ -0,0 +1,52 @@
{
"name": "@flecks/build",
"version": "3.0.0",
"scripts": {
"build": "NODE_PATH=./node_modules webpack --config ./build/build.webpack.config.js --mode production",
"clean": "rm -rf dist yarn.lock && yarn",
"lint": "NODE_PATH=./node_modules eslint --config ./build/eslint.config.js .",
"postversion": "cp package.json dist",
"test": "npm run build -d && mocha -t 10000 --colors ./dist/test.js"
},
"bin": {
"flecks": "./build/cli.js"
},
"files": [
"server.js"
],
"dependencies": {
"@babel/core": "^7.12.10",
"@babel/eslint-parser": "^7.23.3",
"@babel/eslint-plugin": "^7.22.10",
"@babel/plugin-transform-regenerator": "^7.16.7",
"@babel/preset-env": "^7.12.11",
"@flecks/core": "^3.0.0",
"babel-loader": "^9.1.3",
"babel-merge": "^3.0.0",
"chai": "4.2.0",
"chai-as-promised": "7.1.1",
"commander": "11.1.0",
"copy-webpack-plugin": "^11.0.0",
"enhanced-resolve": "^5.9.2",
"eslint": "^7.0.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-base": "^15.0.0",
"eslint-import-resolver-webpack": "^0.13.8",
"eslint-plugin-import": "^2.29.0",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-webpack-plugin": "^3.2.0",
"glob": "^10.3.10",
"globals": "^13.23.0",
"graceful-fs": "^4.2.11",
"js-yaml": "4.1.0",
"mocha": "^8.3.2",
"rimraf": "^3.0.2",
"source-map-loader": "4.0.1",
"source-map-support": "0.5.19",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4",
"webpack-node-externals": "^3.0.0"
}
}

View File

@ -0,0 +1,5 @@
export {dump as dumpYml, load as loadYml} from 'js-yaml';
export {default as webpack} from 'webpack';
export * from '../build/webpack';

View File

@ -2,8 +2,8 @@ import {join} from 'path';
import {expect} from 'chai';
import explicate from '@flecks/core/build/explicate';
import Resolver from '@flecks/core/build/resolver';
import explicate from '@flecks/build/build/explicate';
import Resolver from '@flecks/build/build/resolver';
const {
FLECKS_CORE_ROOT = process.cwd(),

View File

@ -2,7 +2,7 @@ import {join} from 'path';
import {expect} from 'chai';
import Resolver from '@flecks/core/build/resolver';
import Resolver from '@flecks/build/build/resolver';
const {
FLECKS_CORE_ROOT = process.cwd(),

View File

@ -1,4 +0,0 @@
const defaultConfigFn = require('./default.eslint.config');
const Server = require('./server');
module.exports = defaultConfigFn(Server.from());

View File

@ -1,10 +1,10 @@
const Server = require('./server');
const configFn = require('./fleck.webpack.config');
const {executable} = require('./webpack');
const Build = require('../../build/build/build');
const configFn = require('../../build/build/fleck.webpack.config');
const {ProcessAssets} = require('../../build/build/process-assets');
module.exports = async (env, argv) => {
const flecks = await Server.from();
const flecks = await Build.from();
const config = await configFn(env, argv, flecks);
config.plugins.push(...executable());
config.plugins.push(new ProcessAssets());
return config;
};

View File

@ -21,7 +21,7 @@ module.exports = (name) => {
D.formatters.o = undefined;
D.formatters.O = undefined;
}
const type = 'server' === process.env.FLECKS_CORE_BUILD_TARGET ? 'error' : 'debug';
const type = 'web' === process.env.FLECKS_CORE_BUILD_TARGET ? 'debug' : 'error';
// eslint-disable-next-line no-console
D.log = console[type].bind(console);
}

View File

@ -1,63 +1,14 @@
const {join} = require('path');
const {inspect: {defaultOptions}} = require('util');
const webpack = require('webpack');
const {commands} = require('./commands');
const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
defaultOptions.breakLength = 160;
defaultOptions.compact = 6;
defaultOptions.sorted = true;
exports.hooks = {
'@flecks/core.exts': () => ['.mjs', '.js', '.json', '.wasm'],
'@flecks/core.build': async (target, config, env, argv, flecks) => {
if (flecks.get('@flecks/core.profile').includes(target)) {
config.plugins.push(
new webpack.debug.ProfilingPlugin({
outputPath: join(FLECKS_CORE_ROOT, `profile.build-${target}.json`),
}),
);
}
if (Object.entries(flecks.compiled).length > 0) {
config.resolve.symlinks = false;
}
},
'@flecks/core.build.config': () => [
/**
* Babel configuration. See: https://babeljs.io/docs/en/config-files
*/
'babel.config.js',
/**
* ESLint defaults. The generated `eslint.config.js` just reads from this file so that the
* build can dynamically configure parts of ESLint.
*/
'default.eslint.config.js',
/**
* ESLint configuration managed by flecks to allow async.
*/
'eslint.config.js',
/**
* Flecks webpack configuration. See: https://webpack.js.org/configuration/
*/
'fleckspack.config.js',
/**
* Fleck build configuration. See: https://webpack.js.org/configuration/
*/
'fleck.webpack.config.js',
],
'@flecks/core.commands': commands,
'@flecks/core.config': () => ({
/**
* The ID of your application.
*/
id: 'flecks',
/**
* The package manager used for tasks.
*/
packageManager: 'npm',
/**
* Build targets to profile with `webpack.debug.ProfilingPlugin`.
*/
profile: [],
}),
};

View File

@ -462,6 +462,26 @@ exports.Flecks = class Flecks {
.reduce((r, fleck) => ({...r, [fleck]: this.invokeFleck(hook, fleck, ...args)}), {});
}
/**
* Return an object whose keys are fleck paths and values are the `await`ed result of invoking the hook.
* @param {string} hook
* @param {...any} args Arguments passed to each implementation.
* @returns {*}
*/
async invokeAsync(hook, ...args) {
if (!this.hooks[hook]) {
return {};
}
return this.flecksImplementing(hook)
.reduce(
async (r, fleck) => ({
...(await r),
[fleck]: await this.invokeFleck(hook, fleck, ...args),
}),
{},
);
}
/**
* See: [function composition](https://www.educative.io/edpresso/function-composition-in-javascript).
*

View File

@ -0,0 +1,2 @@
'@flecks/build:../build': {}
'@flecks/core:.': {}

View File

@ -12,13 +12,10 @@
"main": "index.js",
"author": "cha0s",
"license": "MIT",
"bin": {
"flecks": "./build/cli.js"
},
"scripts": {
"build": "NODE_PATH=./node_modules webpack --config ./build/core.webpack.config.js --mode production",
"clean": "rm -rf dist bun.lockb && bun install",
"lint": "NODE_PATH=./node_modules eslint --config ./build/eslint.config.js .",
"clean": "rm -rf yarn.lock && yarn",
"lint": "NODE_PATH=./node_modules eslint --config ../build/build/eslint.config.js .",
"postversion": "cp package.json dist",
"test": "npm run build -d && mocha -t 10000 --colors ./dist/test.js"
},
@ -34,6 +31,15 @@
"test"
],
"dependencies": {
"debug": "4.3.1",
"glob": "^10.3.10",
"jsonparse": "^1.3.1",
"lodash.get": "^4.4.2",
"lodash.set": "^4.3.2",
"source-map-support": "0.5.19",
"supports-color": "9.2.1"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/eslint-parser": "^7.23.3",
"@babel/eslint-plugin": "^7.22.10",
@ -43,10 +49,7 @@
"babel-merge": "^3.0.0",
"chai": "4.2.0",
"chai-as-promised": "7.1.1",
"commander": "11.1.0",
"copy-webpack-plugin": "^11.0.0",
"debug": "4.3.1",
"enhanced-resolve": "^5.9.2",
"eslint": "^7.0.0",
"eslint-config-airbnb": "^19.0.4",
"eslint-config-airbnb-base": "^15.0.0",
@ -56,19 +59,10 @@
"eslint-plugin-react": "^7.33.2",
"eslint-plugin-react-hooks": "^4.6.0",
"eslint-webpack-plugin": "^3.2.0",
"glob": "^10.3.10",
"globals": "^13.23.0",
"graceful-fs": "^4.2.11",
"js-yaml": "4.1.0",
"jsonparse": "^1.3.1",
"lodash.get": "^4.4.2",
"lodash.set": "^4.3.2",
"mocha": "^8.3.2",
"null-loader": "^4.0.1",
"rimraf": "^3.0.2",
"source-map-loader": "4.0.1",
"source-map-support": "0.5.19",
"supports-color": "9.2.1",
"webpack": "^5.89.0",
"webpack-cli": "^5.1.4",
"webpack-node-externals": "^3.0.0"

View File

@ -1,27 +1,11 @@
import {inspect} from 'util';
import webpack from 'webpack';
const {defaultOptions} = inspect;
defaultOptions.breakLength = 160;
defaultOptions.compact = 6;
defaultOptions.sorted = true;
export {glob} from 'glob';
export {dump as dumpYml, load as loadYml} from 'js-yaml';
export {commands, processCode, spawnWith} from '../../build/commands';
export {JsonStream, transform} from '../../build/stream';
export * from '../../build/webpack';
export {webpack};
export const hooks = {
'@flecks/web.config': async (req, flecks) => ({
'@flecks/core': {
id: flecks.get('@flecks/core.id'),
packageManager: undefined,
profile: undefined,
},
}),
};

View File

@ -1,10 +1,10 @@
const {copy, executable} = require('@flecks/core/server');
const {copy, executable} = require('@flecks/build/server');
// eslint-disable-next-line import/no-extraneous-dependencies
const configFn = require('@flecks/fleck/build/fleck.webpack.config');
module.exports = async (env, argv, flecks) => {
const config = await configFn(env, argv, flecks);
config.plugins.push(...executable());
config.plugins.push(executable());
config.plugins.push(copy({
patterns: [
{

View File

@ -29,6 +29,7 @@
"validate-npm-package-name": "^3.0.0"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -14,6 +14,7 @@
"@flecks/server": "3.0.0"
},
"devDependencies": {
"@flecks/build": "3.0.0",
"@flecks/create-fleck": "3.0.0",
"lerna": "^3.22.1"
}

View File

@ -3,9 +3,9 @@
const {stat} = require('fs/promises');
const {join} = require('path');
const addFleckToYml = require('@flecks/core/build/add-fleck-to-yml');
const {program} = require('@flecks/core/build/commands');
const Server = require('@flecks/core/build/server');
const Build = require('@flecks/build/build/build');
const addFleckToYml = require('@flecks/build/build/add-fleck-to-yml');
const {program} = require('@flecks/build/build/commands');
const {transform} = require('@flecks/core/server');
const build = require('@flecks/create-app/build/build');
const {move, testDestination} = require('@flecks/create-app/build/move');
@ -67,7 +67,7 @@ const target = async (fleck) => {
program.action(async (fleck, o) => {
const {alias, add} = o;
try {
const flecks = await Server.from();
const flecks = await Build.from();
const {packageManager} = flecks.get('@flecks/core');
const isMonorepo = await checkIsMonorepo();
const [scope, pkg] = await target(fleck);

View File

@ -1,10 +1,10 @@
const {copy, executable} = require('@flecks/core/server');
const {copy, executable} = require('@flecks/build/server');
// eslint-disable-next-line import/no-extraneous-dependencies
const configFn = require('@flecks/fleck/build/fleck.webpack.config');
module.exports = async (env, argv, flecks) => {
const config = await configFn(env, argv, flecks);
config.plugins.push(...executable());
config.plugins.push(executable());
config.plugins.push(copy({
patterns: [
{

View File

@ -27,6 +27,7 @@
"@flecks/create-app": "^3.0.0"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -14,6 +14,7 @@
"@flecks/core": "3.0.0"
},
"devDependencies": {
"@flecks/build": "3.0.0",
"@flecks/fleck": "3.0.0"
}
}

View File

@ -25,6 +25,7 @@
"sqlite3": "^5.0.2"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -1,7 +1,7 @@
const FlecksDockerOutput = require('./plugin');
exports.hooks = {
'@flecks/core.build': (target, config, env, argv, flecks) => {
'@flecks/build.config': (target, config, env, argv, flecks) => {
if ('server' !== target) {
return;
}

View File

@ -1,4 +1,4 @@
const {dumpYml} = require('@flecks/core/server');
const {dumpYml} = require('@flecks/build/server');
const {generateComposeConfig, generateDockerFile} = require('./generate');

View File

@ -25,6 +25,7 @@
"debug": "^4.3.3"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -2,7 +2,7 @@ import startContainer from './start-container';
export const hooks = {
'@flecks/server.up': async (flecks) => {
if (!flecks.get('@flecks/docker/server.enabled')) {
if (!flecks.get('@flecks/docker.enabled')) {
return;
}
const containers = await flecks.invokeMergeAsync('@flecks/docker.containers');

View File

@ -7,8 +7,6 @@ const {
} = require('fs/promises');
const {dirname, join} = require('path');
const {Argument} = require('@flecks/core/build/commands');
const {
generate,
resolveSiteDir,
@ -21,7 +19,7 @@ const {
module.exports = (program, flecks) => {
const commands = {};
const siteDirArgument = new Argument('[siteDir]', 'Docusaurus directory');
const siteDirArgument = program.createArgument('[siteDir]', 'Docusaurus directory');
siteDirArgument.defaultValue = 'website';
commands.docusaurus = {
description: 'create a documentation website for this project',
@ -79,7 +77,8 @@ module.exports = (program, flecks) => {
}
},
args: [
new Argument('subcommand', 'Docusaurus command to run').choices(['build', 'create', 'start']),
program.createArgument('subcommand', 'Docusaurus command to run')
.choices(['build', 'create', 'start']),
siteDirArgument,
],
};

View File

@ -1,7 +1,7 @@
const commands = require('./commands');
exports.hooks = {
'@flecks/core.commands': commands,
'@flecks/build.commands': commands,
'@flecks/core.config': () => ({
/**
* Rewrite the output filenames of source files.

View File

@ -96,7 +96,7 @@ const implementationVisitor = (fn) => ({
const FlecksBuildConfigs = (state) => (
implementationVisitor((property) => {
if ('@flecks/core.build.config' === property.key.value) {
if ('@flecks/build.files' === property.key.value) {
if (isArrowFunctionExpression(property.value)) {
if (isArrayExpression(property.value.body)) {
property.value.body.elements.forEach((element) => {

View File

@ -39,6 +39,7 @@
"rimraf": "^5.0.5"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -1,9 +1,9 @@
const {join} = require('path');
const {banner} = require('@flecks/core/server');
const {banner} = require('@flecks/build/server');
exports.hooks = {
'@flecks/core.build': (target, config) => {
'@flecks/build.config': (target, config) => {
if ('server' === target) {
config.plugins.push(
banner({
@ -38,7 +38,7 @@ exports.hooks = {
*/
url: undefined,
}),
'@flecks/core.build.alter': (configs) => {
'@flecks/build.config.alter': (configs) => {
const {server: config} = configs;
if (config) {
const plugin = config.plugins.find(({pluginName}) => pluginName === 'StartServerPlugin');

View File

@ -25,6 +25,7 @@
"electron-devtools-installer": "^3.2.0"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -1,13 +1,14 @@
const {stat, unlink} = require('fs/promises');
const {join} = require('path');
const {commands: coreCommands} = require('@flecks/build/build/commands');
const {D} = require('@flecks/core');
const {commands: coreCommands, glob} = require('@flecks/core/server');
const {glob} = require('@flecks/core/server');
const chokidar = require('chokidar');
const clearModule = require('clear-module');
const Mocha = require('mocha');
const debug = D('@flecks/core.commands');
const debug = D('@flecks/build.commands');
const {
FLECKS_CORE_ROOT = process.cwd(),

View File

@ -1,6 +1,6 @@
const flecksConfigFn = require('@flecks/core/build/fleck.webpack.config');
const flecksConfigFn = require('@flecks/build/build/fleck.webpack.config');
const ProcessAssets = require('./process-assets');
const {ProcessAssets} = require('@flecks/build/build/process-assets');
module.exports = async (env, argv, flecks) => {
const config = await flecksConfigFn(env, argv, flecks);

View File

@ -1,15 +1,11 @@
const {join} = require('path');
const {glob} = require('@flecks/core/server');
const {hook} = require('@flecks/build/build/process-assets');
const commands = require('./commands');
const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
exports.hooks = {
'@flecks/core.commands': commands,
'@flecks/build.commands': commands,
'@flecks/core.config': () => ({
/**
* Webpack stats configuration.
@ -20,36 +16,5 @@ exports.hooks = {
},
}),
'@flecks/core.targets': () => ['fleck'],
'@flecks/fleck.processAssets': async (assets, compilation, flecks) => {
const {RawSource} = compilation.compiler.webpack.sources;
const packageJson = assets['package.json'];
const json = JSON.parse(packageJson.source().toString());
const {files} = json;
// Add defaults.
files.push('build');
// Add source if it exists.
if ((await glob(join(FLECKS_CORE_ROOT, 'src/**/*.js'))).length > 0) {
files.push('src');
}
// Add tests if they exist.
const testFiles = await glob(join(FLECKS_CORE_ROOT, 'test/**/*.js'));
if (testFiles.length > 0) {
files.push('test');
}
// Let others have a say.
await flecks.invokeSequentialAsync('@flecks/fleck.packageJson', json, compilation);
// Add any sourcemaps.
json.files = json.files
.map((filename) => {
const maybeWithMap = [filename];
if (compilation.assets[`${filename}.map`]) {
maybeWithMap.push(`${filename}.map`);
}
return maybeWithMap;
})
.flat();
// Sort and uniquify.
json.files = [...new Set(json.files.sort((l, r) => (l < r ? -1 : 1)))];
compilation.updateAsset('package.json', new RawSource(JSON.stringify(json, null, 2)));
},
'@flecks/build.processAssets': hook,
};

View File

@ -1,2 +0,0 @@
'@flecks/core': {}
'@flecks/fleck:.': {}

View File

@ -1,28 +0,0 @@
class ProcessAssets {
constructor(flecks) {
this.flecks = flecks;
}
apply(compiler) {
compiler.hooks.thisCompilation.tap('@flecks/fleck/build/process-assets', (compilation) => {
compilation.hooks.processAssets.tapAsync(
{
name: '@flecks/fleck/build/process-assets',
stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_REPORT,
},
async (assets, callback) => {
await this.flecks.invokeSequentialAsync(
'@flecks/fleck.processAssets',
assets,
compilation,
);
callback();
},
);
});
}
}
module.exports = ProcessAssets;

View File

@ -27,6 +27,7 @@
"mocha": "^8.3.2"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"chai": "4.2.0"
}
}

View File

@ -24,10 +24,11 @@
"dependencies": {
"@flecks/core": "^3.0.0",
"@flecks/db": "^3.0.0",
"rate-limiter-flexible": "^2.1.13",
"redis": "^3.1.2"
"@flecks/redis": "^3.0.0",
"rate-limiter-flexible": "^2.1.13"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -1,16 +1,13 @@
import {createClient} from 'redis';
import {createClient} from '@flecks/redis/server';
import {RateLimiterRedis} from 'rate-limiter-flexible';
export default async (flecks, options) => {
const {
host,
port,
} = flecks.get('@flecks/redis/server');
const storeClient = createClient({host, port});
// @todo node-redis@4
// await storeClient.connect();
const storeClient = await createClient(flecks);
const legacyClient = storeClient.duplicate({legacyMode: true});
await legacyClient.connect();
return new RateLimiterRedis({
...options,
storeClient,
// @todo node-redis@4
storeClient: legacyClient,
});
};

View File

@ -1,4 +1,5 @@
import {ByType, Flecks} from '@flecks/core';
import {RateLimiterRes} from 'rate-limiter-flexible';
import LimitedPacket from './limited-packet';
import createLimiter from './limiter';
@ -25,34 +26,41 @@ export const hooks = {
},
}),
'@flecks/db/server.models': Flecks.provide(require.context('./models', false, /\.js$/)),
'@flecks/web/server.request.route': (flecks) => {
const {web} = flecks.get('@flecks/governor/server');
return async (req, res, next) => {
const {Ban} = flecks.db.Models;
try {
await Ban.check(req);
}
catch (error) {
res.status(403).send(`<pre>${error.message}</pre>`);
return;
}
req.ban = async (keys, ttl = 0) => {
const ban = Ban.fromRequest(req, keys, ttl);
await Ban.create({...ban});
res.status(403).send(`<pre>${Ban.format([ban])}</pre>`);
'@flecks/web/server.request.route': Flecks.priority(
(flecks) => {
const {web} = flecks.get('@flecks/governor/server');
return async (req, res, next) => {
const {Ban} = flecks.db.Models;
try {
await Ban.check(req);
}
catch (error) {
res.status(403).send(`<pre>${error.message}</pre>`);
return;
}
req.ban = async (keys, ttl = 0) => {
const ban = Ban.fromRequest(req, keys, ttl);
await Ban.create({...ban});
res.status(403).send(`<pre>${Ban.format([ban])}</pre>`);
};
try {
await flecks.governor.web.consume(req.ip);
next();
}
catch (error) {
console.log(error);
if (!(error instanceof RateLimiterRes)) {
throw error;
}
const {ttl, keys} = web;
const ban = Ban.fromRequest(req, keys, ttl);
await Ban.create({...ban});
res.status(429).send(`<pre>${Ban.format([ban])}</pre>`);
}
};
try {
await flecks.governor.web.consume(req.ip);
next();
}
catch (error) {
const {ttl, keys} = web;
const ban = Ban.fromRequest(req, keys, ttl);
await Ban.create({...ban});
res.status(429).send(`<pre>${Ban.format([ban])}</pre>`);
}
};
},
},
{after: '@flecks/passport/server'},
),
'@flecks/server.up': Flecks.priority(
async (flecks) => {
if (flecks.fleck('@flecks/web/server')) {
@ -91,7 +99,7 @@ export const hooks = {
);
}
},
{after: '@flecks/redis/server'},
{before: '@flecks/web/server', after: '@flecks/redis/server'},
),
'@flecks/socket/server.request.socket': (flecks) => (
async (socket, next) => {
@ -113,6 +121,9 @@ export const hooks = {
next();
}
catch (error) {
if (!(error instanceof RateLimiterRes)) {
throw error;
}
const {ttl, keys} = socket;
await Ban.create(Ban.fromRequest(req, keys, ttl));
next(error);

View File

@ -1,3 +0,0 @@
'@flecks/core': {}
'@flecks/fleck': {}
'@flecks/react': {}

View File

@ -22,9 +22,11 @@
"dependencies": {
"@flecks/core": "^3.0.0",
"@flecks/passport-local": "^3.0.0",
"@flecks/passport-react": "^3.0.0",
"@flecks/react": "^3.0.0"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -26,6 +26,7 @@
"passport-local": "^1.0.0"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -27,6 +27,7 @@
"@flecks/web": "^3.0.0"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -28,6 +28,7 @@
"passport": "^0.7.0"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -38,7 +38,7 @@ export const hooks = {
});
});
},
{after: '@flecks/session/server'},
{after: '@flecks/session/server', before: '@flecks/redux/server'},
),
'@flecks/server.up': Flecks.priority(
async (flecks) => {

View File

@ -19,11 +19,11 @@ exports.hooks = {
'@babel/preset-react',
],
}),
'@flecks/core.build': (target, config, env, argv) => {
'@flecks/build.config': (target, config, env, argv) => {
const isProduction = 'production' === argv.mode;
if (!isProduction) {
config.plugins.push(new ReactRefreshWebpackPlugin());
}
},
'@flecks/core.exts': () => ['.jsx'],
'@flecks/build.extensions': () => ['.jsx'],
};

View File

@ -49,6 +49,7 @@
"redux-first-history": "5.1.1"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -28,6 +28,7 @@
"redis": "4.0.3"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -1,12 +1,19 @@
import {createClient} from 'redis';
export default (flecks, opts = {}) => {
export default async (flecks, opts = {}) => {
const {
host,
port,
} = flecks.get('@flecks/redis/server');
return createClient({
const client = createClient({
url: `redis://${host}:${port}`,
...opts,
});
const promise = new Promise((resolve, reject) => {
client.on('ready', resolve);
client.on('error', reject);
});
await client.connect();
await promise;
return client;
};

View File

@ -3,6 +3,8 @@ import {Flecks} from '@flecks/core';
import containers from './containers';
import createClient from './create-client';
export {default as redis} from 'redis';
export {createClient};
const safeKeys = async (client, pattern, caret) => {
@ -39,18 +41,12 @@ export const hooks = {
port: 6379,
}),
'@flecks/docker.containers': containers,
'@flecks/repl.context': (flecks) => ({
redisClient: createClient(flecks),
'@flecks/repl.context': async (flecks) => ({
redisClient: await createClient(flecks),
}),
'@flecks/server.up': Flecks.priority(
async (flecks) => {
const client = createClient(flecks);
const promise = new Promise((resolve, reject) => {
client.on('ready', resolve);
client.on('error', reject);
});
await client.connect();
await promise;
const client = await createClient(flecks);
await client.disconnect();
},
{after: '@flecks/docker/server'},

View File

@ -17,16 +17,14 @@ export const hooks = {
}
},
'@flecks/session.config': async (flecks) => {
const client = createClient(flecks, {legacyMode: true});
await client.connect();
const client = await createClient(flecks, {legacyMode: true});
return {
store: new RedisStore({client}),
};
},
'@flecks/socket.server': async (flecks) => {
const pubClient = createClient(flecks);
const subClient = createClient(flecks);
await Promise.all([pubClient.connect(), subClient.connect()]);
const pubClient = await createClient(flecks);
const subClient = await createClient(flecks);
debugSilly('creating adapter');
return {
adapter: redisAdapter(pubClient, subClient),

View File

@ -31,6 +31,7 @@
"reduce-reducers": "^1.0.4"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -1,5 +1,5 @@
const commands = require('./commands');
exports.hooks = {
'@flecks/core.commands': commands,
'@flecks/build.commands': commands,
};

View File

@ -25,6 +25,7 @@
"debug": "4.3.1"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -11,7 +11,7 @@ const debugSilly = debug.extend('silly');
export async function createReplServer(flecks) {
const {id} = flecks.get('@flecks/core');
const context = flecks.invokeFlat('@flecks/repl.context')
const context = (await Promise.all(flecks.invokeFlat('@flecks/repl.context')))
.reduce((r, vars) => ({...r, ...vars}), {flecks});
debug(
'Object.keys(context) === %O',

View File

@ -1,5 +1,5 @@
exports.hooks = {
'@flecks/core.build.config': () => [
'@flecks/build.files': () => [
/**
* Server build configuration. See: https://webpack.js.org/configuration/
*/

View File

@ -1,7 +1,7 @@
const {externals} = require('@flecks/core/server');
const {externals} = require('@flecks/build/server');
module.exports = async (config, env, argv, flecks) => {
const runtime = await flecks.resolver.resolve('@flecks/server/runtime');
const runtimePath = await flecks.resolver.resolve('@flecks/server/runtime');
// Inject flecks configuration.
const paths = Object.keys(flecks.flecks);
const resolvedPaths = (await Promise.all(
@ -9,19 +9,45 @@ module.exports = async (config, env, argv, flecks) => {
))
.filter(([, resolved]) => resolved)
.map(([path]) => path);
const runtime = {
config: JSON.stringify(flecks.config),
loadFlecks: [
'async () => (',
' Object.fromEntries(',
' (await Promise.all(',
' [',
...resolvedPaths.map((path) => [
' (async () => {',
' try {',
` return ['${path}', await import('${path}')];`,
' }',
' catch (error) {',
' if (!error.message.startsWith("Cannot find module")) {',
' throw error;',
' }',
' }',
' })(),',
]).flat(),
' ],',
' ))',
' .filter((entry) => entry),',
' )',
')',
].join('\n'),
stubs: (
JSON.stringify(flecks.stubs.map((stub) => (
stub instanceof RegExp ? [stub.source, stub.flags] : stub
)))
),
...await flecks.invokeAsync('@flecks/server.runtime'),
};
const runtimeString = `{${
Object.entries(runtime)
.map(([key, value]) => `"${key}": ${value}`).join(', ')
}}`;
const source = [
"process.env.FLECKS_CORE_BUILD_TARGET = 'server';",
'module.exports = (async () => ({',
` config: ${JSON.stringify(flecks.realiasedConfig)},`,
' loadFlecks: async () => Object.fromEntries(await Promise.all([',
...resolvedPaths.map((path) => (
` ['${path}', import('${path}')],`
)),
' ].map(async ([path, M]) => [path, await M]))),',
` stubs: ${JSON.stringify(flecks.stubs.map((stub) => (
stub instanceof RegExp ? [stub.source, stub.flags] : stub
)))}`,
'}))();',
`module.exports = (async () => (${runtimeString}))();`,
];
// HMR.
source.push('if (module.hot) {');
@ -55,10 +81,10 @@ module.exports = async (config, env, argv, flecks) => {
// Create runtime.
config.module.rules.push(
{
test: runtime,
test: runtimePath,
use: [
{
loader: runtime,
loader: runtimePath,
options: {
source: source.join('\n'),
},
@ -71,14 +97,14 @@ module.exports = async (config, env, argv, flecks) => {
'@flecks/server/runtime',
/^@babel\/runtime\/helpers\/esm/,
];
config.resolve.alias['@flecks/server/runtime$'] = runtime;
config.resolve.alias['@flecks/server/runtime$'] = runtimePath;
const nodeExternalsConfig = {
allowlist,
};
await flecks.runtimeCompiler('server', config, nodeExternalsConfig);
// Rewrite to signals for HMR.
if ('production' !== argv.mode) {
allowlist.push(/^webpack/);
allowlist.push(/^webpack\/hot\/signal/);
}
// Externalize the rest.
config.externals = externals(nodeExternalsConfig);

View File

@ -4,7 +4,7 @@ const {
banner,
defaultConfig,
webpack,
} = require('@flecks/core/server');
} = require('@flecks/build/server');
const runtime = require('./runtime');
const startServer = require('./start');

View File

@ -26,6 +26,7 @@
"@flecks/core": "^3.0.0"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -2,13 +2,13 @@ import {mkdir} from 'fs/promises';
import {tmpdir} from 'os';
import {join} from 'path';
import {D} from '@flecks/core';
import Server from '@flecks/core/build/server';
import {D, Flecks} from '@flecks/core';
const {version} = require('../package.json');
(async () => {
const {config, loadFlecks, stubs} = await __non_webpack_require__('@flecks/server/runtime');
const runtime = await __non_webpack_require__('@flecks/server/runtime');
const {config, loadFlecks, stubs} = runtime;
// eslint-disable-next-line no-console
console.log(`flecks server v${version}`);
try {
@ -26,7 +26,7 @@ const {version} = require('../package.json');
debug('stubbing with %O', unserializedStubs);
__non_webpack_require__('@flecks/core/build/stub')(unserializedStubs);
}
global.flecks = await Server.from({config, flecks: await loadFlecks()});
global.flecks = await Flecks.from({...runtime, flecks: await loadFlecks()});
try {
await Promise.all(global.flecks.invokeFlat('@flecks/core.starting'));
await global.flecks.invokeSequentialAsync('@flecks/server.up');

View File

@ -25,6 +25,7 @@
"express-session": "^1.17.3"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -32,6 +32,7 @@
"socket.io-client": "^4.1.2"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -1,4 +1,4 @@
const {copy, externals} = require('@flecks/core/server');
const {copy, externals} = require('@flecks/build/server');
// eslint-disable-next-line import/no-extraneous-dependencies
const configFn = require('@flecks/fleck/build/fleck.webpack.config');

View File

@ -1,7 +1,9 @@
const {stat, unlink} = require('fs/promises');
const {join} = require('path');
const {regexFromExtensions, spawnWith} = require('@flecks/core/server');
const Build = require('@flecks/build/build/build');
const {spawnWith} = require('@flecks/build/build/commands');
const {regexFromExtensions} = require('@flecks/build/server');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const {
@ -9,7 +11,7 @@ const {
} = process.env;
exports.hooks = {
'@flecks/core.build': async (target, config, env, argv, flecks) => {
'@flecks/build.config': async (target, config, env, argv, flecks) => {
const isProduction = 'production' === argv.mode;
let finalLoader;
switch (target) {
@ -107,7 +109,7 @@ exports.hooks = {
type: 'asset',
});
},
'@flecks/core.build.alter': async (configs, env, argv, flecks) => {
'@flecks/build.config.alter': async (configs, env, argv, flecks) => {
const isProduction = 'production' === argv.mode;
// Only build vendor in dev.
if (configs['web-vendor']) {
@ -187,7 +189,7 @@ exports.hooks = {
// Remove the build config since we're handing off to WDS.
delete configs.web;
},
'@flecks/core.build.config': () => [
'@flecks/build.files': () => [
/**
* Template file used to generate the client HTML.
*
@ -290,6 +292,11 @@ exports.hooks = {
*/
trust: false,
}),
'@flecks/build.packageJson': (json, compilation) => {
if (Object.keys(compilation.assets).some((filename) => filename.match(/^assets\//))) {
json.files.push('assets');
}
},
'@flecks/core.targets': (flecks) => [
'web',
...(flecks.get('@flecks/web.dll').length > 0 ? ['web-vendor'] : []),
@ -300,10 +307,12 @@ exports.hooks = {
targets.delete('web');
}
},
'@flecks/fleck.packageJson': (json, compilation) => {
if (Object.keys(compilation.assets).some((filename) => filename.match(/^assets\//))) {
json.files.push('assets');
}
'@flecks/server.runtime': async (flecks) => {
const {config} = await Build.from({
config: flecks.config,
platforms: ['client', '!server'],
});
return JSON.stringify(config);
},
};

View File

@ -6,11 +6,11 @@ const {
join,
} = require('path');
const Server = require('@flecks/core/build/server');
const Build = require('@flecks/build/build/build');
const {glob} = require('@flecks/core/server');
module.exports = async (config, env, argv, flecks) => {
const buildFlecks = await Server.from({
const buildFlecks = await Build.from({
config: flecks.realiasedConfig,
platforms: ['client', '!server'],
});

View File

@ -1,6 +1,6 @@
const {join} = require('path');
const {defaultConfig, webpack} = require('@flecks/core/server');
const {defaultConfig, webpack} = require('@flecks/build/server');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const {

View File

@ -4,7 +4,7 @@ const {
defaultConfig,
regexFromExtensions,
webpack,
} = require('@flecks/core/server');
} = require('@flecks/build/server');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {htmlTagObjectToString} = require('html-webpack-plugin/lib/html-tags');
@ -81,7 +81,7 @@ module.exports = async (env, argv, flecks) => {
.map(async ([name, mainsConfig]) => {
const {entry: entryPoint, ...htmlTemplateConfig} = mainsConfig;
// @todo source maps working?
entry[name] = [entryPoint];
entry[name] = ['source-map-support/register', entryPoint];
plugins.push(new HtmlWebpackPlugin({
appMountId: flecks.interpolate(appMountId),
base: flecks.interpolate(base),

View File

@ -45,6 +45,7 @@
"lodash.flatten": "^4.4.0",
"mini-css-extract-plugin": "^2.7.6",
"mocha": "^8.3.2",
"null-loader": "^4.0.1",
"path-browserify": "^1.0.1",
"postcss-loader": "4.2.0",
"process": "^0.11.10",
@ -57,6 +58,7 @@
"webpack-dev-server": "^4.15.1"
},
"devDependencies": {
"@flecks/build": "^3.0.0",
"@flecks/fleck": "^3.0.0"
}
}

View File

@ -1,6 +1,3 @@
// eslint-disable-next-line import/no-extraneous-dependencies
require('source-map-support/register');
const mochaDiv = window.document.createElement('div');
mochaDiv.id = 'mocha';
window.document.body.appendChild(mochaDiv);

Some files were not shown because too many files have changed in this diff Show More