refactor: bootstrap
This commit is contained in:
parent
5d2bc3ee07
commit
757cd89e99
|
@ -20,6 +20,10 @@
|
||||||
"@flecks/electron": "*",
|
"@flecks/electron": "*",
|
||||||
"@flecks/fleck": "*",
|
"@flecks/fleck": "*",
|
||||||
"@flecks/governor": "*",
|
"@flecks/governor": "*",
|
||||||
|
"@flecks/passport": "*",
|
||||||
|
"@flecks/passport-local": "*",
|
||||||
|
"@flecks/passport-local-react": "*",
|
||||||
|
"@flecks/passport-react": "*",
|
||||||
"@flecks/react": "*",
|
"@flecks/react": "*",
|
||||||
"@flecks/redis": "*",
|
"@flecks/redis": "*",
|
||||||
"@flecks/redux": "*",
|
"@flecks/redux": "*",
|
||||||
|
@ -27,10 +31,6 @@
|
||||||
"@flecks/server": "*",
|
"@flecks/server": "*",
|
||||||
"@flecks/session": "*",
|
"@flecks/session": "*",
|
||||||
"@flecks/socket": "*",
|
"@flecks/socket": "*",
|
||||||
"@flecks/passport": "*",
|
|
||||||
"@flecks/passport-local": "*",
|
|
||||||
"@flecks/passport-local-react": "*",
|
|
||||||
"@flecks/passport-react": "*",
|
|
||||||
"@flecks/web": "*"
|
"@flecks/web": "*"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
19
packages/core/build/add-fleck-to-yml.js
Normal file
19
packages/core/build/add-fleck-to-yml.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
const {readFile, writeFile} = require('fs/promises');
|
||||||
|
const {
|
||||||
|
join,
|
||||||
|
sep,
|
||||||
|
} = require('path');
|
||||||
|
|
||||||
|
const {dump: dumpYml, load: loadYml} = require('js-yaml');
|
||||||
|
|
||||||
|
const {
|
||||||
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
|
module.exports = async (fleck, path) => {
|
||||||
|
const key = [fleck].concat(path ? `.${sep}${join('packages', path, 'src')}` : []).join(':');
|
||||||
|
const ymlPath = join(FLECKS_CORE_ROOT, 'build', 'flecks.yml');
|
||||||
|
let yml = loadYml(await readFile(ymlPath));
|
||||||
|
yml = Object.fromEntries(Object.entries(yml).concat([[key, {}]]));
|
||||||
|
await writeFile(ymlPath, dumpYml(yml, {sortKeys: true}));
|
||||||
|
};
|
1
packages/core/build/class.js
Normal file
1
packages/core/build/class.js
Normal file
|
@ -0,0 +1 @@
|
||||||
|
module.exports = class {};
|
67
packages/core/build/cli.js
Executable file
67
packages/core/build/cli.js
Executable file
|
@ -0,0 +1,67 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const {Command} = require('commander');
|
||||||
|
|
||||||
|
const {processCode} = require('./commands');
|
||||||
|
const D = require('./debug');
|
||||||
|
const Server = require('./server');
|
||||||
|
|
||||||
|
const debug = D('@flecks/core/cli');
|
||||||
|
const debugSilly = debug.extend('silly');
|
||||||
|
|
||||||
|
// Asynchronous command process code forwarding.
|
||||||
|
const forwardProcessCode = (fn) => async (...args) => {
|
||||||
|
const child = await fn(...args);
|
||||||
|
if ('object' !== typeof child) {
|
||||||
|
const code = 'undefined' !== typeof child ? child : 0;
|
||||||
|
debugSilly('action returned code %d', code);
|
||||||
|
process.exitCode = code;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const code = await processCode(child);
|
||||||
|
debugSilly('action exited with code %d', code);
|
||||||
|
process.exitCode = code;
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(error);
|
||||||
|
process.exitCode = child.exitCode || 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Initialize Commander.
|
||||||
|
const program = new Command();
|
||||||
|
program
|
||||||
|
.enablePositionalOptions()
|
||||||
|
.name('flecks')
|
||||||
|
.usage('[command] [...]');
|
||||||
|
// Bootstrap.
|
||||||
|
(async () => {
|
||||||
|
debugSilly('bootstrapping flecks...');
|
||||||
|
const flecks = await Server.from();
|
||||||
|
debugSilly('bootstrapped');
|
||||||
|
// Register commands.
|
||||||
|
const commands = flecks.invokeMerge('@flecks/core.commands', program);
|
||||||
|
const keys = Object.keys(commands).sort();
|
||||||
|
for (let i = 0; i < keys.length; ++i) {
|
||||||
|
const {
|
||||||
|
action,
|
||||||
|
args = [],
|
||||||
|
description,
|
||||||
|
name = keys[i],
|
||||||
|
options = [],
|
||||||
|
} = commands[keys[i]];
|
||||||
|
debugSilly('adding command %s...', name);
|
||||||
|
const cmd = program.command(name);
|
||||||
|
cmd.description(description);
|
||||||
|
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));
|
||||||
|
}
|
||||||
|
// Parse commandline.
|
||||||
|
program.parse(process.argv);
|
||||||
|
})();
|
|
@ -1,13 +1,12 @@
|
||||||
import {spawn} from 'child_process';
|
const {spawn} = require('child_process');
|
||||||
import {join, normalize} from 'path';
|
const {join, normalize} = require('path');
|
||||||
|
|
||||||
import {Argument} from 'commander';
|
const {Argument, Option, program} = require('commander');
|
||||||
import {glob} from 'glob';
|
const {glob} = require('glob');
|
||||||
import flatten from 'lodash.flatten';
|
const rimraf = require('rimraf');
|
||||||
import rimraf from 'rimraf';
|
|
||||||
|
|
||||||
import D from '../debug';
|
const D = require('./debug');
|
||||||
import Flecks from './flecks';
|
const addFleckToYml = require('./add-fleck-to-yml');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
|
@ -17,32 +16,8 @@ const debug = D('@flecks/core/commands');
|
||||||
const debugSilly = debug.extend('silly');
|
const debugSilly = debug.extend('silly');
|
||||||
const flecksRoot = normalize(FLECKS_CORE_ROOT);
|
const flecksRoot = normalize(FLECKS_CORE_ROOT);
|
||||||
|
|
||||||
export {Argument, Option, program} from 'commander';
|
exports.commands = (program, flecks) => {
|
||||||
|
const {packageManager} = flecks.get('@flecks/core');
|
||||||
export const processCode = (child) => new Promise((resolve, reject) => {
|
|
||||||
child.on('error', reject);
|
|
||||||
child.on('exit', (code) => {
|
|
||||||
child.off('error', reject);
|
|
||||||
resolve(code);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
export const spawnWith = (cmd, opts = {}) => {
|
|
||||||
debug("spawning: '%s'", cmd.join(' '));
|
|
||||||
debugSilly('with options: %O', opts);
|
|
||||||
const child = spawn(cmd[0], cmd.slice(1), {
|
|
||||||
stdio: 'inherit',
|
|
||||||
...opts,
|
|
||||||
env: {
|
|
||||||
...process.env,
|
|
||||||
...opts.env,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
return child;
|
|
||||||
};
|
|
||||||
|
|
||||||
export default (program, flecks) => {
|
|
||||||
const {packageManager} = flecks.get('@flecks/core/server');
|
|
||||||
const commands = {
|
const commands = {
|
||||||
add: {
|
add: {
|
||||||
args: [
|
args: [
|
||||||
|
@ -58,8 +33,8 @@ export default (program, flecks) => {
|
||||||
args.push(packageManager, ['install', fleck]);
|
args.push(packageManager, ['install', fleck]);
|
||||||
}
|
}
|
||||||
args.push({stdio: 'inherit'});
|
args.push({stdio: 'inherit'});
|
||||||
await processCode(spawn(...args));
|
await module.exports.processCode(spawn(...args));
|
||||||
await Flecks.addFleckToYml(fleck);
|
await addFleckToYml(fleck);
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
clean: {
|
clean: {
|
||||||
|
@ -83,11 +58,11 @@ export default (program, flecks) => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
const targets = flatten(flecks.invokeFlat('@flecks/core.targets'));
|
const {targets} = flecks;
|
||||||
if (targets.length > 0) {
|
if (targets.length > 0) {
|
||||||
commands.build = {
|
commands.build = {
|
||||||
args: [
|
args: [
|
||||||
new Argument('[target]', 'build target').choices(targets),
|
new Argument('[target]', 'build target').choices(targets.map(([, target]) => target)),
|
||||||
],
|
],
|
||||||
options: [
|
options: [
|
||||||
['-d, --no-production', 'dev build'],
|
['-d, --no-production', 'dev build'],
|
||||||
|
@ -95,21 +70,21 @@ export default (program, flecks) => {
|
||||||
['-w, --watch', 'watch for changes'],
|
['-w, --watch', 'watch for changes'],
|
||||||
],
|
],
|
||||||
description: 'build a target in your application',
|
description: 'build a target in your application',
|
||||||
action: (target, opts) => {
|
action: async (target, opts) => {
|
||||||
const {
|
const {
|
||||||
hot,
|
hot,
|
||||||
production,
|
production,
|
||||||
watch,
|
watch,
|
||||||
} = opts;
|
} = opts;
|
||||||
debug('Building...', opts);
|
debug('Building...', opts);
|
||||||
const webpackConfig = flecks.buildConfig('fleckspack.config.js');
|
const webpackConfig = await flecks.resolveBuildConfig('fleckspack.config.js');
|
||||||
const cmd = [
|
const cmd = [
|
||||||
'npx', 'webpack',
|
'npx', 'webpack',
|
||||||
'--config', webpackConfig,
|
'--config', webpackConfig,
|
||||||
'--mode', (production && !hot) ? 'production' : 'development',
|
'--mode', (production && !hot) ? 'production' : 'development',
|
||||||
...((watch || hot) ? ['--watch'] : []),
|
...((watch || hot) ? ['--watch'] : []),
|
||||||
];
|
];
|
||||||
return spawnWith(
|
return module.exports.spawnWith(
|
||||||
cmd,
|
cmd,
|
||||||
{
|
{
|
||||||
env: {
|
env: {
|
||||||
|
@ -131,16 +106,17 @@ export default (program, flecks) => {
|
||||||
if (0 === packages.length) {
|
if (0 === packages.length) {
|
||||||
packages.push('.');
|
packages.push('.');
|
||||||
}
|
}
|
||||||
|
await Promise.all(
|
||||||
packages
|
packages
|
||||||
.map((pkg) => join(process.cwd(), pkg))
|
.map((pkg) => join(process.cwd(), pkg))
|
||||||
.forEach((cwd) => {
|
.map(async (cwd) => {
|
||||||
const cmd = [
|
const cmd = [
|
||||||
'npx', 'eslint',
|
'npx', 'eslint',
|
||||||
'--config', flecks.buildConfig('eslint.config.js'),
|
'--config', await flecks.resolveBuildConfig('eslint.config.js'),
|
||||||
'.',
|
'.',
|
||||||
];
|
];
|
||||||
promises.push(new Promise((resolve, reject) => {
|
promises.push(new Promise((resolve, reject) => {
|
||||||
const child = spawnWith(
|
const child = module.exports.spawnWith(
|
||||||
cmd,
|
cmd,
|
||||||
{
|
{
|
||||||
cwd,
|
cwd,
|
||||||
|
@ -152,7 +128,8 @@ export default (program, flecks) => {
|
||||||
resolve(code);
|
resolve(code);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
});
|
}),
|
||||||
|
);
|
||||||
const promise = Promise.all(promises)
|
const promise = Promise.all(promises)
|
||||||
.then(
|
.then(
|
||||||
(codes) => (
|
(codes) => (
|
||||||
|
@ -176,3 +153,29 @@ export default (program, flecks) => {
|
||||||
};
|
};
|
||||||
return commands;
|
return commands;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.processCode = (child) => new Promise((resolve, reject) => {
|
||||||
|
child.on('error', reject);
|
||||||
|
child.on('exit', (code) => {
|
||||||
|
child.off('error', reject);
|
||||||
|
resolve(code);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
exports.spawnWith = (cmd, opts = {}) => {
|
||||||
|
debug("spawning: '%s'", cmd.join(' '));
|
||||||
|
debugSilly('with options: %O', opts);
|
||||||
|
const child = spawn(cmd[0], cmd.slice(1), {
|
||||||
|
stdio: 'inherit',
|
||||||
|
...opts,
|
||||||
|
env: {
|
||||||
|
...process.env,
|
||||||
|
...opts.env,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
return child;
|
||||||
|
};
|
||||||
|
|
||||||
|
exports.Argument = Argument;
|
||||||
|
exports.Option = Option;
|
||||||
|
exports.program = program;
|
|
@ -1,4 +1,4 @@
|
||||||
export default function compose(...funcs) {
|
module.exports = function compose(...funcs) {
|
||||||
if (funcs.length === 0) {
|
if (funcs.length === 0) {
|
||||||
return (arg) => arg;
|
return (arg) => arg;
|
||||||
}
|
}
|
||||||
|
@ -6,4 +6,4 @@ export default function compose(...funcs) {
|
||||||
return funcs[0];
|
return funcs[0];
|
||||||
}
|
}
|
||||||
return funcs.reduce((a, b) => (...args) => a(b(...args)));
|
return funcs.reduce((a, b) => (...args) => a(b(...args)));
|
||||||
}
|
};
|
4
packages/core/build/core.eslint.config.js
Normal file
4
packages/core/build/core.eslint.config.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
const defaultConfigFn = require('./default.eslint.config');
|
||||||
|
const Server = require('./server');
|
||||||
|
|
||||||
|
module.exports = defaultConfigFn(Server.from());
|
10
packages/core/build/core.webpack.config.js
Normal file
10
packages/core/build/core.webpack.config.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
const Server = require('./server');
|
||||||
|
const configFn = require('./fleck.webpack.config');
|
||||||
|
const {executable} = require('./webpack');
|
||||||
|
|
||||||
|
module.exports = async (env, argv) => {
|
||||||
|
const flecks = await Server.from();
|
||||||
|
const config = await configFn(env, argv, flecks);
|
||||||
|
config.plugins.push(...executable());
|
||||||
|
return config;
|
||||||
|
};
|
74
packages/core/build/default.eslint.config.js
Normal file
74
packages/core/build/default.eslint.config.js
Normal file
|
@ -0,0 +1,74 @@
|
||||||
|
const globals = require('globals');
|
||||||
|
|
||||||
|
module.exports = async (flecks) => ({
|
||||||
|
extends: [
|
||||||
|
require.resolve('eslint-config-airbnb'),
|
||||||
|
require.resolve('eslint-config-airbnb/hooks'),
|
||||||
|
],
|
||||||
|
globals: {
|
||||||
|
...globals.browser,
|
||||||
|
...globals.es2021,
|
||||||
|
...globals.mocha,
|
||||||
|
...globals.node,
|
||||||
|
__non_webpack_require__: true,
|
||||||
|
},
|
||||||
|
ignorePatterns: [
|
||||||
|
'dist/**',
|
||||||
|
// Not even gonna try.
|
||||||
|
'build/dox/hooks.js',
|
||||||
|
],
|
||||||
|
overrides: [
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'build/**/*.js',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'import/no-dynamic-require': 'off',
|
||||||
|
'global-require': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
files: [
|
||||||
|
'test/**/*.js',
|
||||||
|
],
|
||||||
|
rules: {
|
||||||
|
'brace-style': 'off',
|
||||||
|
'class-methods-use-this': 'off',
|
||||||
|
'import/no-extraneous-dependencies': 'off',
|
||||||
|
'import/no-unresolved': 'off',
|
||||||
|
'max-classes-per-file': 'off',
|
||||||
|
'no-new': 'off',
|
||||||
|
'no-unused-expressions': 'off',
|
||||||
|
'padded-blocks': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
parser: require.resolve('@babel/eslint-parser'),
|
||||||
|
parserOptions: {
|
||||||
|
requireConfigFile: false,
|
||||||
|
babelOptions: await flecks.babel(),
|
||||||
|
},
|
||||||
|
plugins: ['@babel'],
|
||||||
|
rules: {
|
||||||
|
'brace-style': ['error', 'stroustrup'],
|
||||||
|
// Bug: https://github.com/import-js/eslint-plugin-import/issues/2181
|
||||||
|
'import/no-import-module-exports': 'off',
|
||||||
|
'import/prefer-default-export': 'off',
|
||||||
|
'jsx-a11y/control-has-associated-label': ['error', {assert: 'either'}],
|
||||||
|
'jsx-a11y/label-has-associated-control': ['error', {assert: 'either'}],
|
||||||
|
'no-param-reassign': ['error', {props: false}],
|
||||||
|
'no-plusplus': 'off',
|
||||||
|
'no-shadow': 'off',
|
||||||
|
'object-curly-spacing': 'off',
|
||||||
|
'padded-blocks': ['error', {classes: 'always'}],
|
||||||
|
yoda: 'off',
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
'import/resolver': {
|
||||||
|
node: {},
|
||||||
|
},
|
||||||
|
react: {
|
||||||
|
version: '18.2.0',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
|
@ -87,4 +87,4 @@ class Digraph {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Digraph;
|
module.exports = Digraph;
|
|
@ -68,7 +68,7 @@ Have fun!
|
||||||
|
|
||||||
## Resolution order 🤔
|
## Resolution order 🤔
|
||||||
|
|
||||||
The flecks server provides an interface (`flecks.buildConfig()`) for gathering configuration files
|
The flecks server provides an interface (`flecks.resolveBuildConfig()`) for gathering configuration files
|
||||||
from the `build` directory. The resolution order is determined by a few variables:
|
from the `build` directory. The resolution order is determined by a few variables:
|
||||||
|
|
||||||
- `filename` specifies the name of the configuration file, e.g. `server.webpack.config.js`.
|
- `filename` specifies the name of the configuration file, e.g. `server.webpack.config.js`.
|
||||||
|
|
|
@ -1,3 +1,71 @@
|
||||||
const defaultConfigFn = require('../src/server/build/default.eslint.config');
|
const {spawnSync} = require('child_process');
|
||||||
|
const {
|
||||||
|
mkdirSync,
|
||||||
|
readFileSync,
|
||||||
|
statSync,
|
||||||
|
writeFileSync,
|
||||||
|
} = require('fs');
|
||||||
|
const {join} = require('path');
|
||||||
|
|
||||||
module.exports = defaultConfigFn();
|
const D = require('./debug');
|
||||||
|
const Server = require('./server');
|
||||||
|
|
||||||
|
const debug = D('@flecks/core/build/eslint.config.js');
|
||||||
|
|
||||||
|
const {
|
||||||
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
|
FLECKS_CORE_SYNC_FOR_ESLINT = false,
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
|
// This is kinda nuts, but ESLint doesn't support its configuration files returning a promise!
|
||||||
|
if (FLECKS_CORE_SYNC_FOR_ESLINT) {
|
||||||
|
(async () => {
|
||||||
|
debug('bootstrapping flecks...');
|
||||||
|
const flecks = await Server.from();
|
||||||
|
debug('bootstrapped');
|
||||||
|
// Load and finalize ESLint configuration.
|
||||||
|
const eslintConfig = await require(
|
||||||
|
await flecks.resolveBuildConfig('default.eslint.config.js'),
|
||||||
|
)(flecks);
|
||||||
|
const {resolve} = await require(
|
||||||
|
await flecks.resolveBuildConfig('fleck.webpack.config.js'),
|
||||||
|
)({}, {mode: 'development'}, flecks);
|
||||||
|
eslintConfig.settings['import/resolver'].webpack = {config: {resolve}};
|
||||||
|
// Write it out to stdout.
|
||||||
|
process.stdout.write(JSON.stringify(eslintConfig, null, 2));
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Check cache first.
|
||||||
|
const cacheDirectory = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'core');
|
||||||
|
try {
|
||||||
|
statSync(join(cacheDirectory, 'eslint.config.json'));
|
||||||
|
module.exports = JSON.parse(readFileSync(join(cacheDirectory, 'eslint.config.json')).toString());
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
// Just silly. By synchronously spawning... ourselves, the child can use async.
|
||||||
|
const {stderr, stdout} = spawnSync('node', [__filename], {
|
||||||
|
env: {
|
||||||
|
FLECKS_CORE_SYNC_FOR_ESLINT: true,
|
||||||
|
NODE_PATH: join(FLECKS_CORE_ROOT, 'node_modules'),
|
||||||
|
...process.env,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(stderr.toString());
|
||||||
|
// Read the JSON written out to stdout.
|
||||||
|
const json = stdout.toString();
|
||||||
|
try {
|
||||||
|
const parsed = JSON.parse(json);
|
||||||
|
statSync(join(FLECKS_CORE_ROOT, 'node_modules'));
|
||||||
|
mkdirSync(cacheDirectory, {recursive: true});
|
||||||
|
// Cache.
|
||||||
|
writeFileSync(join(cacheDirectory, 'eslint.config.json'), json);
|
||||||
|
module.exports = parsed;
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.error(error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ const createListener = (fn, that, type, once) => ({
|
||||||
bound: that ? fn.bind(that) : fn,
|
bound: that ? fn.bind(that) : fn,
|
||||||
});
|
});
|
||||||
|
|
||||||
export default function EventEmitterDecorator(Superclass) {
|
module.exports = function EventEmitterDecorator(Superclass) {
|
||||||
|
|
||||||
return class EventEmitter extends Superclass {
|
return class EventEmitter extends Superclass {
|
||||||
|
|
||||||
|
@ -123,4 +123,4 @@ export default function EventEmitterDecorator(Superclass) {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
};
|
135
packages/core/build/explicate.js
Normal file
135
packages/core/build/explicate.js
Normal file
|
@ -0,0 +1,135 @@
|
||||||
|
const {
|
||||||
|
join,
|
||||||
|
resolve,
|
||||||
|
} = require('path');
|
||||||
|
|
||||||
|
module.exports = async function explicate(
|
||||||
|
maybeAliasedPaths,
|
||||||
|
{
|
||||||
|
importer,
|
||||||
|
platforms = ['server'],
|
||||||
|
resolver,
|
||||||
|
root,
|
||||||
|
},
|
||||||
|
) {
|
||||||
|
const descriptors = {};
|
||||||
|
const seen = {};
|
||||||
|
const roots = {};
|
||||||
|
function createDescriptor(maybeAliasedPath) {
|
||||||
|
const index = maybeAliasedPath.indexOf(':');
|
||||||
|
return -1 === index
|
||||||
|
? {
|
||||||
|
path: maybeAliasedPath,
|
||||||
|
request: maybeAliasedPath,
|
||||||
|
}
|
||||||
|
: {
|
||||||
|
path: maybeAliasedPath.slice(0, index),
|
||||||
|
request: resolve(root, maybeAliasedPath.slice(index + 1)),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
async function doExplication(descriptor) {
|
||||||
|
const {path, request} = descriptor;
|
||||||
|
if (
|
||||||
|
platforms
|
||||||
|
.filter((platform) => platform.startsWith('!'))
|
||||||
|
.map((platform) => platform.slice(1))
|
||||||
|
.includes(path.split('/').pop())
|
||||||
|
) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (path !== request) {
|
||||||
|
resolver.addAlias(path, request);
|
||||||
|
}
|
||||||
|
descriptors[request] = descriptor;
|
||||||
|
}
|
||||||
|
async function getRootDescriptor(descriptor) {
|
||||||
|
const {path, request} = descriptor;
|
||||||
|
// Walk up and find the root, if any.
|
||||||
|
const pathParts = path.split('/');
|
||||||
|
const requestParts = request.split('/');
|
||||||
|
let rootDescriptor;
|
||||||
|
while (pathParts.length > 0 && requestParts.length > 0) {
|
||||||
|
const candidate = requestParts.join('/');
|
||||||
|
// eslint-disable-next-line no-await-in-loop
|
||||||
|
if (await resolver.resolve(join(candidate, 'package.json'))) {
|
||||||
|
rootDescriptor = {
|
||||||
|
path: pathParts.join('/'),
|
||||||
|
request: requestParts.join('/'),
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pathParts.pop();
|
||||||
|
requestParts.pop();
|
||||||
|
}
|
||||||
|
return rootDescriptor;
|
||||||
|
}
|
||||||
|
function descriptorsAreTheSame(l, r) {
|
||||||
|
return (l && !r) || (!l && r) ? false : l.request === r.request;
|
||||||
|
}
|
||||||
|
async function explicateDescriptor(descriptor) {
|
||||||
|
if (descriptors[descriptor.request] || seen[descriptor.request]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
seen[descriptor.request] = true;
|
||||||
|
const areDescriptorsTheSame = descriptorsAreTheSame(
|
||||||
|
descriptor,
|
||||||
|
await getRootDescriptor(descriptor),
|
||||||
|
);
|
||||||
|
const resolved = await resolver.resolve(descriptor.request);
|
||||||
|
if (resolved || areDescriptorsTheSame) {
|
||||||
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
await explicateRoot(descriptor);
|
||||||
|
}
|
||||||
|
if (!resolved && areDescriptorsTheSame) {
|
||||||
|
descriptors[descriptor.request] = descriptor;
|
||||||
|
}
|
||||||
|
if (resolved) {
|
||||||
|
await doExplication(descriptor);
|
||||||
|
}
|
||||||
|
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),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
async function explicateRoot(descriptor) {
|
||||||
|
// Walk up and find the root, if any.
|
||||||
|
const rootDescriptor = await getRootDescriptor(descriptor);
|
||||||
|
if (!rootDescriptor || roots[rootDescriptor.request]) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {request} = rootDescriptor;
|
||||||
|
roots[request] = true;
|
||||||
|
// Import bootstrap script.
|
||||||
|
const bootstrapPath = await resolver.resolve(join(request, 'build', 'flecks.bootstrap'));
|
||||||
|
const bootstrap = bootstrapPath ? importer(bootstrapPath) : {};
|
||||||
|
roots[request] = bootstrap;
|
||||||
|
// Explicate dependcies.
|
||||||
|
const {dependencies = []} = bootstrap;
|
||||||
|
if (dependencies.length > 0) {
|
||||||
|
await Promise.all(
|
||||||
|
dependencies
|
||||||
|
.map(createDescriptor)
|
||||||
|
.map(explicateDescriptor),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
await explicateDescriptor(rootDescriptor);
|
||||||
|
}
|
||||||
|
await Promise.all(
|
||||||
|
maybeAliasedPaths
|
||||||
|
.map(createDescriptor)
|
||||||
|
.map(explicateDescriptor),
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
descriptors,
|
||||||
|
roots,
|
||||||
|
};
|
||||||
|
};
|
|
@ -5,34 +5,28 @@ const {
|
||||||
join,
|
join,
|
||||||
} = require('path');
|
} = require('path');
|
||||||
|
|
||||||
const babelmerge = require('babel-merge');
|
|
||||||
const CopyPlugin = require('copy-webpack-plugin');
|
const CopyPlugin = require('copy-webpack-plugin');
|
||||||
const glob = require('glob');
|
const glob = require('glob');
|
||||||
|
|
||||||
const D = require('../../debug');
|
const {defaultConfig, externals, regexFromExtensions} = require('./webpack');
|
||||||
const R = require('../../require');
|
|
||||||
const {defaultConfig, externals, regexFromExtensions} = require('../webpack');
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
} = process.env;
|
} = process.env;
|
||||||
|
|
||||||
const debug = D('@flecks/core/server/build/fleck.webpack.config.js');
|
|
||||||
const debugSilly = debug.extend('silly');
|
|
||||||
|
|
||||||
const source = join(FLECKS_CORE_ROOT, 'src');
|
const source = join(FLECKS_CORE_ROOT, 'src');
|
||||||
const tests = join(FLECKS_CORE_ROOT, 'test');
|
const tests = join(FLECKS_CORE_ROOT, 'test');
|
||||||
|
|
||||||
const resolveValidModulePath = (source) => (path) => {
|
const resolveValidModulePath = (source) => (path) => {
|
||||||
// Does the file resolve as source?
|
// Does the file resolve as source?
|
||||||
try {
|
try {
|
||||||
R.resolve(`${source}/${path}`);
|
require.resolve(`${source}/${path}`);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
const ext = extname(path);
|
const ext = extname(path);
|
||||||
// Try the implicit [path]/index[.ext] variation.
|
// Try the implicit [path]/index[.ext] variation.
|
||||||
try {
|
try {
|
||||||
R.resolve(`${source}/${dirname(path)}/${basename(path, ext)}/index${ext}`);
|
require.resolve(`${source}/${dirname(path)}/${basename(path, ext)}/index${ext}`);
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -41,8 +35,8 @@ const resolveValidModulePath = (source) => (path) => {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = (env, argv, flecks) => {
|
module.exports = async (env, argv, flecks) => {
|
||||||
const {name, files = []} = R(join(FLECKS_CORE_ROOT, 'package.json'));
|
const {name, files = []} = require(join(FLECKS_CORE_ROOT, 'package.json'));
|
||||||
const config = defaultConfig(flecks, {
|
const config = defaultConfig(flecks, {
|
||||||
externals: externals({importType: 'umd'}),
|
externals: externals({importType: 'umd'}),
|
||||||
node: {
|
node: {
|
||||||
|
@ -86,6 +80,9 @@ module.exports = (env, argv, flecks) => {
|
||||||
alias: {
|
alias: {
|
||||||
[name]: source,
|
[name]: source,
|
||||||
},
|
},
|
||||||
|
fallback: {
|
||||||
|
[name]: FLECKS_CORE_ROOT,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
stats: {
|
stats: {
|
||||||
colors: true,
|
colors: true,
|
||||||
|
@ -93,30 +90,7 @@ module.exports = (env, argv, flecks) => {
|
||||||
},
|
},
|
||||||
target: 'node',
|
target: 'node',
|
||||||
});
|
});
|
||||||
const merging = [
|
const babelConfig = await flecks.babel();
|
||||||
{
|
|
||||||
plugins: ['@babel/plugin-syntax-dynamic-import'],
|
|
||||||
presets: [
|
|
||||||
[
|
|
||||||
'@babel/preset-env',
|
|
||||||
{
|
|
||||||
shippedProposals: true,
|
|
||||||
targets: {
|
|
||||||
esmodules: true,
|
|
||||||
node: 'current',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
if (flecks) {
|
|
||||||
merging.push({configFile: flecks.buildConfig('babel.config.js')});
|
|
||||||
const flecksBabelConfig = flecks.babel();
|
|
||||||
debugSilly('flecks.config.js: babel: %j', flecksBabelConfig);
|
|
||||||
merging.push(...flecksBabelConfig.map(([, babel]) => babel));
|
|
||||||
}
|
|
||||||
const babelConfig = babelmerge.all(merging);
|
|
||||||
const extensionsRegex = regexFromExtensions(config.resolve.extensions);
|
const extensionsRegex = regexFromExtensions(config.resolve.extensions);
|
||||||
config.module.rules.push(
|
config.module.rules.push(
|
||||||
{
|
{
|
||||||
|
@ -144,14 +118,12 @@ module.exports = (env, argv, flecks) => {
|
||||||
});
|
});
|
||||||
// Test entry.
|
// Test entry.
|
||||||
const testPaths = glob.sync(join(tests, '*.js'));
|
const testPaths = glob.sync(join(tests, '*.js'));
|
||||||
const platforms = flecks
|
const {platforms} = flecks;
|
||||||
? flecks.platforms
|
|
||||||
: ['server'];
|
|
||||||
for (let i = 0; i < platforms.length; ++i) {
|
for (let i = 0; i < platforms.length; ++i) {
|
||||||
testPaths.push(...glob.sync(join(tests, `platforms/${platforms[i]}/*.js`)));
|
testPaths.push(...glob.sync(join(tests, platforms[i], '*.js')));
|
||||||
}
|
}
|
||||||
if (testPaths.length > 0) {
|
if (testPaths.length > 0) {
|
||||||
config.entry.test = testPaths;
|
config.entry.test = ['source-map-support/register', ...testPaths];
|
||||||
}
|
}
|
||||||
return config;
|
return config;
|
||||||
};
|
};
|
60
packages/core/build/flecks.bootstrap.js
Normal file
60
packages/core/build/flecks.bootstrap.js
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
const {join} = require('path');
|
||||||
|
|
||||||
|
const webpack = require('webpack');
|
||||||
|
|
||||||
|
const {commands} = require('./commands');
|
||||||
|
|
||||||
|
const {
|
||||||
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
|
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`),
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'@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: [],
|
||||||
|
}),
|
||||||
|
};
|
|
@ -1,3 +0,0 @@
|
||||||
module.exports = {
|
|
||||||
exts: ['.mjs', '.js'],
|
|
||||||
};
|
|
|
@ -1,18 +1,18 @@
|
||||||
// eslint-disable-next-line max-classes-per-file
|
// eslint-disable-next-line max-classes-per-file
|
||||||
import {
|
const {
|
||||||
basename,
|
basename,
|
||||||
dirname,
|
dirname,
|
||||||
extname,
|
extname,
|
||||||
join,
|
join,
|
||||||
} from 'path';
|
} = require('path');
|
||||||
|
|
||||||
import get from 'lodash.get';
|
const get = require('lodash.get');
|
||||||
import set from 'lodash.set';
|
const set = require('lodash.set');
|
||||||
|
|
||||||
import compose from './compose';
|
const compose = require('./compose');
|
||||||
import D from './debug';
|
const D = require('./debug');
|
||||||
import Digraph from './digraph';
|
const Digraph = require('./digraph');
|
||||||
import Middleware from './middleware';
|
const Middleware = require('./middleware');
|
||||||
|
|
||||||
const debug = D('@flecks/core/flecks');
|
const debug = D('@flecks/core/flecks');
|
||||||
const debugSilly = debug.extend('silly');
|
const debugSilly = debug.extend('silly');
|
||||||
|
@ -21,8 +21,8 @@ const debugSilly = debug.extend('silly');
|
||||||
const HookPriority = Symbol.for('@flecks/core.hookPriority');
|
const HookPriority = Symbol.for('@flecks/core.hookPriority');
|
||||||
|
|
||||||
// Symbols for Gathered classes.
|
// Symbols for Gathered classes.
|
||||||
export const ById = Symbol.for('@flecks/core.byId');
|
exports.ById = Symbol.for('@flecks/core.byId');
|
||||||
export const ByType = Symbol.for('@flecks/core.byType');
|
exports.ByType = Symbol.for('@flecks/core.byType');
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Capitalize a string.
|
* Capitalize a string.
|
||||||
|
@ -59,7 +59,7 @@ const wrapGathered = (Class, id, idProperty, type, typeProperty) => {
|
||||||
return Subclass;
|
return Subclass;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class Flecks {
|
exports.Flecks = class Flecks {
|
||||||
|
|
||||||
config = {};
|
config = {};
|
||||||
|
|
||||||
|
@ -69,23 +69,19 @@ export default class Flecks {
|
||||||
|
|
||||||
hooks = {};
|
hooks = {};
|
||||||
|
|
||||||
platforms = {};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param {object} init
|
* @param {object} runtime
|
||||||
* @param {object} init.config The Flecks configuration (e.g. loaded from `flecks.yml`).
|
* @param {object} runtime.config configuration (e.g. loaded from `flecks.yml`).
|
||||||
* @param {string[]} init.platforms Platforms this instance is running on.
|
* @param {object} runtime.flecks fleck modules.
|
||||||
*/
|
*/
|
||||||
constructor({
|
constructor({
|
||||||
config = {},
|
config = {},
|
||||||
flecks = {},
|
flecks = {},
|
||||||
platforms = [],
|
|
||||||
} = {}) {
|
} = {}) {
|
||||||
const emptyConfigForAllFlecks = Object.fromEntries(
|
const emptyConfigForAllFlecks = Object.fromEntries(
|
||||||
Object.keys(flecks).map((path) => [path, {}]),
|
Object.keys(flecks).map((path) => [path, {}]),
|
||||||
);
|
);
|
||||||
this.config = {...emptyConfigForAllFlecks, ...config};
|
this.config = {...emptyConfigForAllFlecks, ...config};
|
||||||
this.platforms = platforms;
|
|
||||||
const entries = Object.entries(flecks);
|
const entries = Object.entries(flecks);
|
||||||
debugSilly('paths: %O', entries.map(([fleck]) => fleck));
|
debugSilly('paths: %O', entries.map(([fleck]) => fleck));
|
||||||
for (let i = 0; i < entries.length; i++) {
|
for (let i = 0; i < entries.length; i++) {
|
||||||
|
@ -191,7 +187,6 @@ export default class Flecks {
|
||||||
this.config = {};
|
this.config = {};
|
||||||
this.hooks = {};
|
this.hooks = {};
|
||||||
this.flecks = {};
|
this.flecks = {};
|
||||||
this.platforms = [];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -206,17 +201,9 @@ export default class Flecks {
|
||||||
}
|
}
|
||||||
const flecks = this.lookupFlecks(hook);
|
const flecks = this.lookupFlecks(hook);
|
||||||
let expanded = [];
|
let expanded = [];
|
||||||
// Expand configured flecks.
|
|
||||||
for (let i = 0; i < flecks.length; ++i) {
|
for (let i = 0; i < flecks.length; ++i) {
|
||||||
const fleck = flecks[i];
|
const fleck = flecks[i];
|
||||||
expanded.push(fleck);
|
expanded.push(fleck);
|
||||||
for (let j = 0; j < this.platforms.length; ++j) {
|
|
||||||
const platform = this.platforms[j];
|
|
||||||
const variant = join(fleck, platform);
|
|
||||||
if (this.fleck(variant)) {
|
|
||||||
expanded.push(variant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Handle elision.
|
// Handle elision.
|
||||||
const index = expanded.findIndex((fleck) => '...' === fleck);
|
const index = expanded.findIndex((fleck) => '...' === fleck);
|
||||||
|
@ -238,13 +225,6 @@ export default class Flecks {
|
||||||
if (!expanded.includes(fleck)) {
|
if (!expanded.includes(fleck)) {
|
||||||
elided.push(fleck);
|
elided.push(fleck);
|
||||||
}
|
}
|
||||||
for (let j = 0; j < this.platforms.length; ++j) {
|
|
||||||
const platform = this.platforms[j];
|
|
||||||
const variant = join(fleck, platform);
|
|
||||||
if (this.fleck(variant) && !expanded.includes(variant)) {
|
|
||||||
elided.push(variant);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Map the fleck implementations to vertices in a dependency graph.
|
// Map the fleck implementations to vertices in a dependency graph.
|
||||||
const graph = this.flecksHookGraph([...before, ...elided, ...after], hook);
|
const graph = this.flecksHookGraph([...before, ...elided, ...after], hook);
|
||||||
|
@ -380,13 +360,13 @@ export default class Flecks {
|
||||||
* @param {Object} config Configuration.
|
* @param {Object} config Configuration.
|
||||||
* @returns {Flecks} A flecks instance.
|
* @returns {Flecks} A flecks instance.
|
||||||
*/
|
*/
|
||||||
static from(config) {
|
static from(runtime) {
|
||||||
const {flecks} = config;
|
const {flecks} = runtime;
|
||||||
const mixins = Object.entries(flecks)
|
const mixins = Object.entries(flecks)
|
||||||
.map(([, M]) => M.hooks?.['@flecks/core.mixin'])
|
.map(([, M]) => M.hooks?.['@flecks/core.mixin'])
|
||||||
.filter((e) => e);
|
.filter((e) => e);
|
||||||
const Flecks = compose(...mixins)(this);
|
const Flecks = compose(...mixins)(this);
|
||||||
return new Flecks(config);
|
return new Flecks(runtime);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -431,8 +411,8 @@ export default class Flecks {
|
||||||
const gathered = {
|
const gathered = {
|
||||||
...ids,
|
...ids,
|
||||||
...types,
|
...types,
|
||||||
[ById]: ids,
|
[exports.ById]: ids,
|
||||||
[ByType]: types,
|
[exports.ByType]: types,
|
||||||
};
|
};
|
||||||
// Register for HMR?
|
// Register for HMR?
|
||||||
hotGathered.set(
|
hotGathered.set(
|
||||||
|
@ -444,7 +424,7 @@ export default class Flecks {
|
||||||
gathered,
|
gathered,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
debug("gathered '%s': %O", hook, Object.keys(gathered[ByType]));
|
debug("gathered '%s': %O", hook, Object.keys(gathered[exports.ByType]));
|
||||||
return gathered;
|
return gathered;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -846,7 +826,10 @@ export default class Flecks {
|
||||||
const {[type]: {[idProperty]: id}} = gathered;
|
const {[type]: {[idProperty]: id}} = gathered;
|
||||||
const Subclass = wrapGathered(Class, id, idProperty, type, typeProperty);
|
const Subclass = wrapGathered(Class, id, idProperty, type, typeProperty);
|
||||||
// eslint-disable-next-line no-multi-assign
|
// eslint-disable-next-line no-multi-assign
|
||||||
gathered[type] = gathered[id] = gathered[ById][id] = gathered[ByType][type] = Subclass;
|
gathered[type] = Subclass;
|
||||||
|
gathered[id] = Subclass;
|
||||||
|
gathered[exports.ById][id] = Subclass;
|
||||||
|
gathered[exports.ByType][type] = Subclass;
|
||||||
this.invoke('@flecks/core.hmr.gathered.class', Subclass, hook);
|
this.invoke('@flecks/core.hmr.gathered.class', Subclass, hook);
|
||||||
});
|
});
|
||||||
this.invoke('@flecks/core.hmr.gathered', gathered, hook);
|
this.invoke('@flecks/core.hmr.gathered', gathered, hook);
|
||||||
|
@ -905,7 +888,7 @@ export default class Flecks {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
Flecks.get = get;
|
exports.Flecks.get = get;
|
||||||
Flecks.set = set;
|
exports.Flecks.set = set;
|
|
@ -1,2 +0,0 @@
|
||||||
# This isn't a "real" `flecks.yml`. It only exists for testing purposes.
|
|
||||||
'@flecks/core:./src': {}
|
|
65
packages/core/build/fleckspack.config.js
Normal file
65
packages/core/build/fleckspack.config.js
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
require('source-map-support/register');
|
||||||
|
|
||||||
|
const D = require('./debug');
|
||||||
|
const Server = require('./server');
|
||||||
|
|
||||||
|
const debug = D('@flecks/core/build/fleckspack.config.js');
|
||||||
|
|
||||||
|
const {
|
||||||
|
FLECKS_CORE_BUILD_LIST = '',
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
|
const buildList = FLECKS_CORE_BUILD_LIST
|
||||||
|
.split(',')
|
||||||
|
.map((name) => name.trim())
|
||||||
|
.filter((e) => e);
|
||||||
|
|
||||||
|
module.exports = async (env, argv) => {
|
||||||
|
debug('bootstrapping flecks...');
|
||||||
|
const flecks = await Server.from();
|
||||||
|
debug('bootstrapped');
|
||||||
|
debug('gathering configs');
|
||||||
|
const {targets} = flecks;
|
||||||
|
const building = targets
|
||||||
|
.filter(([, target]) => 0 === buildList.length || buildList.includes(target));
|
||||||
|
debug('building: %O', building.map(([target]) => target));
|
||||||
|
if (0 === building.length) {
|
||||||
|
debug('no build configuration found! aborting...');
|
||||||
|
await new Promise(() => {});
|
||||||
|
}
|
||||||
|
const entries = await Promise.all(building.map(
|
||||||
|
async ([fleck, target]) => {
|
||||||
|
const configFn = require(await flecks.resolveBuildConfig(`${target}.webpack.config.js`, fleck));
|
||||||
|
if ('function' !== typeof configFn) {
|
||||||
|
debug(`'${
|
||||||
|
target
|
||||||
|
}' build configuration expected function got ${
|
||||||
|
typeof configFn
|
||||||
|
}! aborting...`);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return [target, await configFn(env, argv, flecks)];
|
||||||
|
},
|
||||||
|
));
|
||||||
|
await Promise.all(
|
||||||
|
entries.map(async ([target, config]) => (
|
||||||
|
Promise.all(flecks.invokeFlat('@flecks/core.build', target, config, env, argv))
|
||||||
|
)),
|
||||||
|
);
|
||||||
|
const webpackConfigs = Object.fromEntries(entries);
|
||||||
|
await Promise.all(flecks.invokeFlat('@flecks/core.build.alter', webpackConfigs, env, argv));
|
||||||
|
const enterableWebpackConfigs = Object.values(webpackConfigs)
|
||||||
|
.filter((webpackConfig) => {
|
||||||
|
if (!webpackConfig.entry) {
|
||||||
|
debug('webpack configurations %O had no entry... discarding', webpackConfig);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
if (0 === enterableWebpackConfigs.length) {
|
||||||
|
debug('no webpack configuration found! aborting...');
|
||||||
|
await new Promise(() => {});
|
||||||
|
}
|
||||||
|
debug('webpack configurations %O', enterableWebpackConfigs);
|
||||||
|
return enterableWebpackConfigs;
|
||||||
|
};
|
32
packages/core/build/load-config.js
Normal file
32
packages/core/build/load-config.js
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
const {readFile} = require('fs/promises');
|
||||||
|
const {join} = require('path');
|
||||||
|
|
||||||
|
const D = require('./debug');
|
||||||
|
|
||||||
|
const debug = D('@flecks/core:load-config');
|
||||||
|
|
||||||
|
const {
|
||||||
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
|
module.exports = async function loadConfig() {
|
||||||
|
try {
|
||||||
|
const {load} = require('js-yaml');
|
||||||
|
const filename = join(FLECKS_CORE_ROOT, 'build', 'flecks.yml');
|
||||||
|
const buffer = await readFile(filename, 'utf8');
|
||||||
|
debug('parsing configuration from YML...');
|
||||||
|
return ['YML', load(buffer, {filename})];
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
if ('ENOENT' !== error.code) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
const {name} = require(join(FLECKS_CORE_ROOT, 'package.json'));
|
||||||
|
const barebones = {'@flecks/core': {}, '@flecks/fleck': {}};
|
||||||
|
if (barebones[name]) {
|
||||||
|
delete barebones[name];
|
||||||
|
}
|
||||||
|
barebones[`${name}:${FLECKS_CORE_ROOT}`] = {};
|
||||||
|
return ['barebones', barebones];
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
export default class Middleware {
|
module.exports = class Middleware {
|
||||||
|
|
||||||
constructor(middleware = []) {
|
constructor(middleware = []) {
|
||||||
this.middleware = [];
|
this.middleware = [];
|
||||||
|
@ -61,4 +61,4 @@ export default class Middleware {
|
||||||
this.middleware.push(this.constructor.check(fn));
|
this.middleware.push(this.constructor.check(fn));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
};
|
88
packages/core/build/resolver.js
Normal file
88
packages/core/build/resolver.js
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
const {join} = require('path');
|
||||||
|
|
||||||
|
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 debugSilly = debug.extend('silly');
|
||||||
|
|
||||||
|
const {
|
||||||
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
|
const nodeContext = {
|
||||||
|
environments: ['node+es3+es5+process+native'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const nodeFileSystem = new CachedInputFileSystem(fs, 4000);
|
||||||
|
|
||||||
|
module.exports = class Resolver {
|
||||||
|
|
||||||
|
constructor(options) {
|
||||||
|
this.resolver = ResolverFactory.createResolver({
|
||||||
|
conditionNames: ['node'],
|
||||||
|
extensions: ['.js', '.json', '.node'],
|
||||||
|
fileSystem: nodeFileSystem,
|
||||||
|
symlinks: false,
|
||||||
|
...{
|
||||||
|
modules: [join(FLECKS_CORE_ROOT, 'node_modules')],
|
||||||
|
...options,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addAlias(name, alias) {
|
||||||
|
debugSilly("adding alias: '%s' -> '%s'", name, alias);
|
||||||
|
new AliasPlugin(
|
||||||
|
'raw-resolve',
|
||||||
|
{name, onlyModule: false, alias},
|
||||||
|
'internal-resolve',
|
||||||
|
).apply(this.resolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
addExtensions(extensions) {
|
||||||
|
debugSilly("adding extensions: '%O'", extensions);
|
||||||
|
extensions.forEach((extension) => {
|
||||||
|
new AppendPlugin('raw-file', extension, 'file').apply(this);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
addFallback(name, alias) {
|
||||||
|
debugSilly("adding fallback: '%s' -> '%s'", name, alias);
|
||||||
|
new AliasPlugin(
|
||||||
|
'described-resolve',
|
||||||
|
{name, onlyModule: false, alias},
|
||||||
|
'internal-resolve',
|
||||||
|
).apply(this.resolver);
|
||||||
|
}
|
||||||
|
|
||||||
|
static isResolutionError(error) {
|
||||||
|
return error.message.startsWith("Can't resolve");
|
||||||
|
}
|
||||||
|
|
||||||
|
async resolve(request) {
|
||||||
|
try {
|
||||||
|
return await new Promise((resolve, reject) => {
|
||||||
|
this.resolver.resolve(nodeContext, FLECKS_CORE_ROOT, request, {}, (error, path) => {
|
||||||
|
if (error) {
|
||||||
|
reject(error);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
resolve(path);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
if (!this.constructor.isResolutionError(error)) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
318
packages/core/build/server.js
Normal file
318
packages/core/build/server.js
Normal file
|
@ -0,0 +1,318 @@
|
||||||
|
const {realpath} = require('fs/promises');
|
||||||
|
const {join} = require('path');
|
||||||
|
|
||||||
|
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');
|
||||||
|
|
||||||
|
const {
|
||||||
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
|
const debug = D('@flecks/core/build/bootstrap');
|
||||||
|
const debugSilly = debug.extend('silly');
|
||||||
|
|
||||||
|
function environmentalize(path) {
|
||||||
|
return path
|
||||||
|
// - `@flecks/core` -> `flecks_core`
|
||||||
|
.replace(/[^a-zA-Z0-9]/g, '_')
|
||||||
|
.replace(/_*(.*)_*/, '$1');
|
||||||
|
}
|
||||||
|
|
||||||
|
function environmentConfiguration(config) {
|
||||||
|
const keys = Object.keys(process.env);
|
||||||
|
Object.keys(config)
|
||||||
|
.sort((l, r) => (l < r ? 1 : -1))
|
||||||
|
.forEach((fleck) => {
|
||||||
|
const prefix = `FLECKS_ENV__${environmentalize(fleck)}`;
|
||||||
|
keys
|
||||||
|
.filter((key) => key.startsWith(`${prefix}__`))
|
||||||
|
.map((key) => {
|
||||||
|
debug('reading environment from %s...', key);
|
||||||
|
return [key.slice(prefix.length + 2), process.env[key]];
|
||||||
|
})
|
||||||
|
.map(([subkey, value]) => [subkey.split('_'), value])
|
||||||
|
.forEach(([path, jsonOrString]) => {
|
||||||
|
try {
|
||||||
|
set(config, [fleck, ...path], JSON.parse(jsonOrString));
|
||||||
|
debug('read (%s) as JSON', jsonOrString);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
set(config, [fleck, ...path], jsonOrString);
|
||||||
|
debug('read (%s) as string', jsonOrString);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = class Server extends Flecks {
|
||||||
|
|
||||||
|
buildConfigs = {};
|
||||||
|
|
||||||
|
platforms = ['server'];
|
||||||
|
|
||||||
|
resolved = {};
|
||||||
|
|
||||||
|
resolver = new Resolver();
|
||||||
|
|
||||||
|
roots = {};
|
||||||
|
|
||||||
|
async babel() {
|
||||||
|
const merging = [
|
||||||
|
{
|
||||||
|
plugins: ['@babel/plugin-syntax-dynamic-import'],
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
'@babel/preset-env',
|
||||||
|
{
|
||||||
|
shippedProposals: true,
|
||||||
|
targets: {
|
||||||
|
esmodules: true,
|
||||||
|
node: 'current',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
],
|
||||||
|
},
|
||||||
|
];
|
||||||
|
merging.push({configFile: await this.resolveBuildConfig('babel.config.js')});
|
||||||
|
merging.push(...this.invokeFlat('@flecks/core.babel'));
|
||||||
|
return babelmerge.all(merging);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async buildRuntime(originalConfig, platforms, flecks = {}) {
|
||||||
|
const dealiasedConfig = Object.fromEntries(
|
||||||
|
Object.entries(originalConfig)
|
||||||
|
.map(([maybeAliasedPath, config]) => {
|
||||||
|
const index = maybeAliasedPath.indexOf(':');
|
||||||
|
return [
|
||||||
|
-1 === index ? maybeAliasedPath : maybeAliasedPath.slice(0, index),
|
||||||
|
config,
|
||||||
|
];
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const resolver = new Resolver();
|
||||||
|
const explication = await explicate(
|
||||||
|
Object.keys(originalConfig),
|
||||||
|
{
|
||||||
|
platforms,
|
||||||
|
resolver,
|
||||||
|
root: FLECKS_CORE_ROOT,
|
||||||
|
importer: (request) => require(request),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
const runtime = {
|
||||||
|
config: environmentConfiguration(
|
||||||
|
Object.fromEntries(
|
||||||
|
Object.values(explication.descriptors)
|
||||||
|
.map(({path}) => [path, dealiasedConfig[path] || {}]),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
flecks: Object.fromEntries(
|
||||||
|
Object.values(explication.descriptors)
|
||||||
|
.map(({path, request}) => [path, flecks[path] || explication.roots[request] || {}]),
|
||||||
|
),
|
||||||
|
};
|
||||||
|
const resolved = {};
|
||||||
|
await Promise.all(
|
||||||
|
Object.entries(explication.descriptors)
|
||||||
|
.map(async ([, {path, request}]) => {
|
||||||
|
try {
|
||||||
|
if (path !== request || request !== await realpath(request)) {
|
||||||
|
resolved[path] = request;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line no-empty
|
||||||
|
catch (error) {}
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
const reverseRequest = Object.fromEntries(
|
||||||
|
Object.entries(explication.descriptors)
|
||||||
|
.map(([, {path, request}]) => [request, path]),
|
||||||
|
);
|
||||||
|
return {
|
||||||
|
resolved,
|
||||||
|
resolver,
|
||||||
|
roots: Object.fromEntries(
|
||||||
|
Object.entries(explication.roots)
|
||||||
|
.map(([request, bootstrap]) => [reverseRequest[request], {bootstrap, request}]),
|
||||||
|
),
|
||||||
|
runtime,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
get extensions() {
|
||||||
|
return this.invokeFlat('@flecks/core.exts').flat();
|
||||||
|
}
|
||||||
|
|
||||||
|
static async from(
|
||||||
|
{
|
||||||
|
config: configParameter,
|
||||||
|
flecks: configFlecks,
|
||||||
|
platforms = ['server'],
|
||||||
|
} = {},
|
||||||
|
) {
|
||||||
|
// Load or use parameterized configuration.
|
||||||
|
let originalConfig;
|
||||||
|
let configType = 'parameter';
|
||||||
|
if (!configParameter) {
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
[configType, originalConfig] = await loadConfig();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
originalConfig = JSON.parse(JSON.stringify(configParameter));
|
||||||
|
}
|
||||||
|
debug('bootstrap configuration (%s)', configType);
|
||||||
|
debugSilly(originalConfig);
|
||||||
|
const {
|
||||||
|
resolved,
|
||||||
|
resolver,
|
||||||
|
roots,
|
||||||
|
runtime,
|
||||||
|
} = await this.buildRuntime(originalConfig, platforms, configFlecks);
|
||||||
|
const flecks = super.from(runtime);
|
||||||
|
flecks.roots = roots;
|
||||||
|
flecks.platforms = platforms;
|
||||||
|
flecks.resolved = resolved;
|
||||||
|
flecks.resolver = resolver;
|
||||||
|
flecks.loadBuildConfigs();
|
||||||
|
return flecks;
|
||||||
|
}
|
||||||
|
|
||||||
|
loadBuildConfigs() {
|
||||||
|
Object.entries(this.invoke('@flecks/core.build.config'))
|
||||||
|
.forEach(([fleck, configs]) => {
|
||||||
|
configs.forEach((config) => {
|
||||||
|
this.buildConfigs[config] = fleck;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
debugSilly('build configs loaded: %O', this.buildConfigs);
|
||||||
|
}
|
||||||
|
|
||||||
|
async resolveBuildConfig(config, override) {
|
||||||
|
const fleck = this.buildConfigs[config];
|
||||||
|
if (!fleck) {
|
||||||
|
throw new Error(`Unknown build config: '${config}'`);
|
||||||
|
}
|
||||||
|
const rootConfig = await this.resolver.resolve(join(FLECKS_CORE_ROOT, 'build', config));
|
||||||
|
if (rootConfig) {
|
||||||
|
return rootConfig;
|
||||||
|
}
|
||||||
|
if (override) {
|
||||||
|
const overrideConfig = await this.resolver.resolve(join(override, 'build', config));
|
||||||
|
if (overrideConfig) {
|
||||||
|
return overrideConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return this.resolver.resolve(join(fleck, 'build', config));
|
||||||
|
}
|
||||||
|
|
||||||
|
async runtimeCompiler(runtime, config, {allowlist = []} = {}) {
|
||||||
|
// Compile.
|
||||||
|
const needCompilation = Object.entries(this.resolved);
|
||||||
|
if (needCompilation.length > 0) {
|
||||||
|
const babelConfig = await this.babel();
|
||||||
|
// const flecksBabelConfig = this.babel();
|
||||||
|
// Alias and de-externalize.
|
||||||
|
await Promise.all(
|
||||||
|
needCompilation
|
||||||
|
.map(async ([fleck, resolved]) => {
|
||||||
|
allowlist.push(fleck);
|
||||||
|
// Create alias.
|
||||||
|
config.resolve.alias[fleck] = resolved;
|
||||||
|
debugSilly('%s runtime de-externalized %s, alias: %s', runtime, fleck, resolved);
|
||||||
|
// Alias this compiled fleck's `node_modules` to the root `node_modules`.
|
||||||
|
config.resolve.alias[
|
||||||
|
join(resolved, 'node_modules')
|
||||||
|
] = join(FLECKS_CORE_ROOT, 'node_modules');
|
||||||
|
config.module.rules.push(
|
||||||
|
{
|
||||||
|
test: /\.(m?jsx?)?$/,
|
||||||
|
include: [resolved],
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: require.resolve('babel-loader'),
|
||||||
|
options: {
|
||||||
|
cacheDirectory: true,
|
||||||
|
babelrc: false,
|
||||||
|
configFile: false,
|
||||||
|
...babelConfig,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
// Our very own lil' chunk.
|
||||||
|
set(config, 'optimization.splitChunks.cacheGroups.flecks-compiled', {
|
||||||
|
chunks: 'all',
|
||||||
|
enforce: true,
|
||||||
|
priority: 100,
|
||||||
|
test: new RegExp(
|
||||||
|
`(?:${
|
||||||
|
Object.keys(this.resolved)
|
||||||
|
.map((path) => path.replace(/[\\/]/g, '[\\/]')).join('|')
|
||||||
|
})`,
|
||||||
|
),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get stubs() {
|
||||||
|
return Object.values(this.flecks)
|
||||||
|
.reduce(
|
||||||
|
(r, {stubs = {}}) => (
|
||||||
|
r.concat(
|
||||||
|
Object.entries(stubs)
|
||||||
|
.reduce(
|
||||||
|
(r, [platform, stubs]) => (
|
||||||
|
r.concat(this.platforms.includes(platform) ? stubs : [])
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
[],
|
||||||
|
).flat();
|
||||||
|
}
|
||||||
|
|
||||||
|
get targets() {
|
||||||
|
const targets = this.invoke('@flecks/core.targets');
|
||||||
|
const duplicates = {};
|
||||||
|
const entries = Object.entries(targets);
|
||||||
|
const set = new Set();
|
||||||
|
entries
|
||||||
|
.forEach(([fleck, targets]) => {
|
||||||
|
targets.forEach((target) => {
|
||||||
|
if (set.has(target)) {
|
||||||
|
if (!duplicates[target]) {
|
||||||
|
duplicates[target] = [];
|
||||||
|
}
|
||||||
|
duplicates[target].push(fleck);
|
||||||
|
}
|
||||||
|
set.add(target);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
const errorMessage = Object.entries(duplicates).map(([target, flecks]) => (
|
||||||
|
`Multiple flecks ('${flecks.join("', '")})' tried to build target '${target}'`
|
||||||
|
)).join('\n');
|
||||||
|
if (errorMessage) {
|
||||||
|
throw new Error(`@flecks/core.targets:\n${errorMessage}`);
|
||||||
|
}
|
||||||
|
this.invoke('@flecks/core.targets.alter', set);
|
||||||
|
return entries
|
||||||
|
.map(([fleck, targets]) => (
|
||||||
|
targets
|
||||||
|
.filter((target) => set.has(target))
|
||||||
|
.map((target) => [fleck, target])
|
||||||
|
)).flat();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
|
@ -1,8 +1,8 @@
|
||||||
// eslint-disable-next-line max-classes-per-file
|
// eslint-disable-next-line max-classes-per-file
|
||||||
import JsonParse from 'jsonparse';
|
const JsonParse = require('jsonparse');
|
||||||
import {Transform} from 'stream';
|
const {Transform} = require('stream');
|
||||||
|
|
||||||
export class JsonStream extends Transform {
|
exports.JsonStream = class JsonStream extends Transform {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
@ -23,9 +23,9 @@ export class JsonStream extends Transform {
|
||||||
this.parser.write(chunk);
|
this.parser.write(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
};
|
||||||
|
|
||||||
JsonStream.PrettyPrint = class extends Transform {
|
exports.JsonStream.PrettyPrint = class extends Transform {
|
||||||
|
|
||||||
constructor(indent = 2) {
|
constructor(indent = 2) {
|
||||||
super();
|
super();
|
||||||
|
@ -40,7 +40,7 @@ JsonStream.PrettyPrint = class extends Transform {
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const transform = (fn, opts = {}) => {
|
exports.transform = (fn, opts = {}) => {
|
||||||
class EasyTransform extends Transform {
|
class EasyTransform extends Transform {
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
15
packages/core/build/stub.js
Normal file
15
packages/core/build/stub.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
module.exports = function stub(stubs) {
|
||||||
|
if (0 === stubs.length) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const {Module} = require('module');
|
||||||
|
const {require: Mr} = Module.prototype;
|
||||||
|
Module.prototype.require = function hackedRequire(request, options) {
|
||||||
|
for (let i = 0; i < stubs.length; ++i) {
|
||||||
|
if (request.match(stubs[i])) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Mr.call(this, request, options);
|
||||||
|
};
|
||||||
|
};
|
|
@ -1,15 +0,0 @@
|
||||||
const configFn = require('../src/server/build/webpack.config');
|
|
||||||
const {executable} = require('../src/server/webpack');
|
|
||||||
const eslintConfigFn = require('../src/server/build/default.eslint.config');
|
|
||||||
|
|
||||||
module.exports = async (env, argv) => {
|
|
||||||
const config = await configFn(env, argv);
|
|
||||||
config.plugins.push(...executable());
|
|
||||||
const eslint = await eslintConfigFn();
|
|
||||||
eslint.settings['import/resolver'].webpack = {
|
|
||||||
config: {
|
|
||||||
resolve: config.resolve,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
return config;
|
|
||||||
};
|
|
|
@ -20,10 +20,7 @@ exports.banner = (options) => (
|
||||||
exports.copy = (options) => (new CopyPlugin(options));
|
exports.copy = (options) => (new CopyPlugin(options));
|
||||||
|
|
||||||
exports.defaultConfig = (flecks, specializedConfig) => {
|
exports.defaultConfig = (flecks, specializedConfig) => {
|
||||||
const extensions = ['.mjs', '.js', '.json', '.wasm'];
|
const {extensions} = flecks;
|
||||||
if (flecks) {
|
|
||||||
extensions.push(...flecks.exts());
|
|
||||||
}
|
|
||||||
const extensionsRegex = exports.regexFromExtensions(extensions);
|
const extensionsRegex = exports.regexFromExtensions(extensions);
|
||||||
const defaults = {
|
const defaults = {
|
||||||
context: FLECKS_CORE_ROOT,
|
context: FLECKS_CORE_ROOT,
|
||||||
|
@ -47,10 +44,10 @@ exports.defaultConfig = (flecks, specializedConfig) => {
|
||||||
alias: {},
|
alias: {},
|
||||||
extensions,
|
extensions,
|
||||||
fallback: {},
|
fallback: {},
|
||||||
modules: [
|
// modules: [
|
||||||
'node_modules',
|
// 'node_modules',
|
||||||
join(FLECKS_CORE_ROOT, 'node_modules'),
|
// join(FLECKS_CORE_ROOT, 'node_modules'),
|
||||||
],
|
// ],
|
||||||
},
|
},
|
||||||
stats: {
|
stats: {
|
||||||
colors: true,
|
colors: true,
|
||||||
|
@ -90,10 +87,6 @@ exports.defaultConfig = (flecks, specializedConfig) => {
|
||||||
|
|
||||||
// Include a shebang and set the executable bit..
|
// Include a shebang and set the executable bit..
|
||||||
exports.executable = () => ([
|
exports.executable = () => ([
|
||||||
exports.banner({
|
|
||||||
banner: '#!/usr/bin/env node',
|
|
||||||
include: /^cli\.js$/,
|
|
||||||
}),
|
|
||||||
new class Executable {
|
new class Executable {
|
||||||
|
|
||||||
// eslint-disable-next-line class-methods-use-this
|
// eslint-disable-next-line class-methods-use-this
|
||||||
|
@ -101,7 +94,7 @@ exports.executable = () => ([
|
||||||
compiler.hooks.afterEmit.tapAsync(
|
compiler.hooks.afterEmit.tapAsync(
|
||||||
'Executable',
|
'Executable',
|
||||||
(compilation, callback) => {
|
(compilation, callback) => {
|
||||||
chmod(join(FLECKS_CORE_ROOT, 'dist', 'cli.js'), 0o755, callback);
|
chmod(join(FLECKS_CORE_ROOT, 'dist', 'build', 'cli.js'), 0o755, callback);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
|
@ -8,38 +8,26 @@
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"version": "2.0.3",
|
"version": "3.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"author": "cha0s",
|
"author": "cha0s",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"bin": {
|
"bin": {
|
||||||
"flecks": "./cli.js"
|
"flecks": "./build/cli.js"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "NODE_PATH=./node_modules webpack --config ./build/webpack.config.js --mode production",
|
"build": "NODE_PATH=./node_modules webpack --config ./build/core.webpack.config.js --mode production",
|
||||||
"clean": "rm -rf dist bun.lockb && bun install",
|
"clean": "rm -rf dist bun.lockb && bun install",
|
||||||
"lint": "NODE_PATH=./node_modules eslint --config ./build/eslint.config.js .",
|
"lint": "NODE_PATH=./node_modules eslint --config ./build/eslint.config.js .",
|
||||||
"postversion": "cp package.json dist",
|
"postversion": "cp package.json dist",
|
||||||
"test": "npm run build && mocha -t 10000 --colors ./dist/test.js"
|
"test": "npm run build -d && mocha -t 10000 --colors ./dist/test.js"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"build",
|
"build",
|
||||||
"cli.js",
|
|
||||||
"cli.js.map",
|
|
||||||
"index.js",
|
"index.js",
|
||||||
"index.js.map",
|
"index.js.map",
|
||||||
"server.js",
|
"server.js",
|
||||||
"server.js.map",
|
"server.js.map",
|
||||||
"server/build/babel.config.js",
|
|
||||||
"server/build/babel.config.js.map",
|
|
||||||
"server/build/default.eslint.config.js",
|
|
||||||
"server/build/default.eslint.config.js.map",
|
|
||||||
"server/build/eslint.config.js",
|
|
||||||
"server/build/eslint.config.js.map",
|
|
||||||
"server/build/webpack.config.js",
|
|
||||||
"server/build/webpack.config.js.map",
|
|
||||||
"server/build/fleckspack.config.js",
|
|
||||||
"server/build/fleckspack.config.js.map",
|
|
||||||
"src",
|
"src",
|
||||||
"start.js",
|
"start.js",
|
||||||
"start.js.map",
|
"start.js.map",
|
||||||
|
@ -51,13 +39,10 @@
|
||||||
"@babel/core": "^7.12.10",
|
"@babel/core": "^7.12.10",
|
||||||
"@babel/eslint-parser": "^7.23.3",
|
"@babel/eslint-parser": "^7.23.3",
|
||||||
"@babel/eslint-plugin": "^7.22.10",
|
"@babel/eslint-plugin": "^7.22.10",
|
||||||
"@babel/plugin-proposal-optional-chaining": "^7.12.16",
|
|
||||||
"@babel/plugin-transform-regenerator": "^7.16.7",
|
"@babel/plugin-transform-regenerator": "^7.16.7",
|
||||||
"@babel/preset-env": "^7.12.11",
|
"@babel/preset-env": "^7.12.11",
|
||||||
"@babel/register": "7.13.0",
|
|
||||||
"babel-loader": "^9.1.3",
|
"babel-loader": "^9.1.3",
|
||||||
"babel-merge": "^3.0.0",
|
"babel-merge": "^3.0.0",
|
||||||
"babel-plugin-prepend": "^1.0.2",
|
|
||||||
"chai": "4.2.0",
|
"chai": "4.2.0",
|
||||||
"chai-as-promised": "7.1.1",
|
"chai-as-promised": "7.1.1",
|
||||||
"commander": "11.1.0",
|
"commander": "11.1.0",
|
||||||
|
@ -72,17 +57,16 @@
|
||||||
"eslint-plugin-jsx-a11y": "^6.8.0",
|
"eslint-plugin-jsx-a11y": "^6.8.0",
|
||||||
"eslint-plugin-react": "^7.33.2",
|
"eslint-plugin-react": "^7.33.2",
|
||||||
"eslint-plugin-react-hooks": "^4.6.0",
|
"eslint-plugin-react-hooks": "^4.6.0",
|
||||||
"eslint-webpack-plugin": "^4.0.1",
|
"eslint-webpack-plugin": "^3.2.0",
|
||||||
"glob": "^10.3.10",
|
"glob": "^10.3.10",
|
||||||
"globals": "^13.23.0",
|
"globals": "^13.23.0",
|
||||||
|
"graceful-fs": "^4.2.11",
|
||||||
"js-yaml": "4.1.0",
|
"js-yaml": "4.1.0",
|
||||||
"jsonparse": "^1.3.1",
|
"jsonparse": "^1.3.1",
|
||||||
"lodash.flatten": "^4.4.0",
|
|
||||||
"lodash.get": "^4.4.2",
|
"lodash.get": "^4.4.2",
|
||||||
"lodash.intersectionby": "4.7.0",
|
|
||||||
"lodash.set": "^4.3.2",
|
"lodash.set": "^4.3.2",
|
||||||
"mocha": "^8.3.2",
|
"mocha": "^8.3.2",
|
||||||
"pirates": "^4.0.5",
|
"null-loader": "^4.0.1",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"source-map-loader": "4.0.1",
|
"source-map-loader": "4.0.1",
|
||||||
"source-map-support": "0.5.19",
|
"source-map-support": "0.5.19",
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
export default class {}
|
|
|
@ -1,116 +0,0 @@
|
||||||
import {fork} from 'child_process';
|
|
||||||
import {join, resolve, sep} from 'path';
|
|
||||||
|
|
||||||
import {Command} from 'commander';
|
|
||||||
|
|
||||||
import D from './debug';
|
|
||||||
import {processCode} from './server/commands';
|
|
||||||
import Flecks from './server/flecks';
|
|
||||||
|
|
||||||
const {
|
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
const debug = D('@flecks/core/cli');
|
|
||||||
const debugSilly = debug.extend('silly');
|
|
||||||
|
|
||||||
// Guarantee local node_modules path.
|
|
||||||
const defaultNodeModules = resolve(join(FLECKS_CORE_ROOT, 'node_modules'));
|
|
||||||
const nodePathSeparator = '/' === sep ? ':' : ';';
|
|
||||||
let updatedNodePath;
|
|
||||||
if (!process.env.NODE_PATH) {
|
|
||||||
updatedNodePath = defaultNodeModules;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const parts = process.env.NODE_PATH.split(nodePathSeparator);
|
|
||||||
if (!parts.some((part) => resolve(part) === defaultNodeModules)) {
|
|
||||||
parts.push(defaultNodeModules);
|
|
||||||
updatedNodePath = parts.join(nodePathSeparator);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Guarantee symlink preservation for linked flecks.
|
|
||||||
const updateSymlinkPreservation = !process.env.NODE_PRESERVE_SYMLINKS;
|
|
||||||
|
|
||||||
const environmentUpdates = (
|
|
||||||
updatedNodePath
|
|
||||||
|| updateSymlinkPreservation
|
|
||||||
)
|
|
||||||
? {
|
|
||||||
NODE_PATH: updatedNodePath,
|
|
||||||
NODE_PRESERVE_SYMLINKS: 1,
|
|
||||||
}
|
|
||||||
: undefined;
|
|
||||||
if (environmentUpdates) {
|
|
||||||
debugSilly('updating environment, forking with %O...', environmentUpdates);
|
|
||||||
const forkOptions = {
|
|
||||||
env: {
|
|
||||||
...process.env,
|
|
||||||
...environmentUpdates,
|
|
||||||
DEBUG_COLORS: 'true',
|
|
||||||
},
|
|
||||||
stdio: 'inherit',
|
|
||||||
};
|
|
||||||
fork(__filename, process.argv.slice(2), forkOptions)
|
|
||||||
.on('exit', (code, signal) => {
|
|
||||||
process.exitCode = code;
|
|
||||||
process.exit(signal);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Asynchronous command process code forwarding.
|
|
||||||
const forwardProcessCode = (fn) => async (...args) => {
|
|
||||||
const child = await fn(...args);
|
|
||||||
if ('object' !== typeof child) {
|
|
||||||
const code = 'undefined' !== typeof child ? child : 0;
|
|
||||||
debugSilly('action returned code %d', code);
|
|
||||||
process.exitCode = code;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const code = await processCode(child);
|
|
||||||
debugSilly('action exited with code %d', code);
|
|
||||||
process.exitCode = code;
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(error);
|
|
||||||
process.exitCode = child.exitCode || 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Initialize Commander.
|
|
||||||
const program = new Command();
|
|
||||||
program
|
|
||||||
.enablePositionalOptions()
|
|
||||||
.name('flecks')
|
|
||||||
.usage('[command] [...]');
|
|
||||||
// Bootstrap.
|
|
||||||
(async () => {
|
|
||||||
debugSilly('bootstrapping flecks...');
|
|
||||||
const flecks = Flecks.bootstrap();
|
|
||||||
debugSilly('bootstrapped');
|
|
||||||
// Register commands.
|
|
||||||
const commands = flecks.invokeMerge('@flecks/core.commands', program);
|
|
||||||
const keys = Object.keys(commands).sort();
|
|
||||||
for (let i = 0; i < keys.length; ++i) {
|
|
||||||
const {
|
|
||||||
action,
|
|
||||||
args = [],
|
|
||||||
description,
|
|
||||||
name = keys[i],
|
|
||||||
options = [],
|
|
||||||
} = commands[keys[i]];
|
|
||||||
debugSilly('adding command %s...', name);
|
|
||||||
const cmd = program.command(name);
|
|
||||||
cmd.description(description);
|
|
||||||
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));
|
|
||||||
}
|
|
||||||
// Parse commandline.
|
|
||||||
program.parse(process.argv);
|
|
||||||
})();
|
|
||||||
}
|
|
|
@ -1,18 +1,9 @@
|
||||||
export {default as Class} from './class';
|
export {default as Class} from '../build/class';
|
||||||
export {default as compose} from './compose';
|
export {default as compose} from '../build/compose';
|
||||||
export {default as D} from './debug';
|
export {default as D} from '../build/debug';
|
||||||
export {default as EventEmitter} from './event-emitter';
|
export {default as EventEmitter} from '../build/event-emitter';
|
||||||
export {
|
export {
|
||||||
default as Flecks,
|
|
||||||
ById,
|
ById,
|
||||||
ByType,
|
ByType,
|
||||||
} from './flecks';
|
Flecks,
|
||||||
|
} from '../build/flecks';
|
||||||
export const hooks = {
|
|
||||||
'@flecks/core.config': () => ({
|
|
||||||
/**
|
|
||||||
* The ID of your application.
|
|
||||||
*/
|
|
||||||
id: 'flecks',
|
|
||||||
}),
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
// Get a runtime require function by hook or by crook. :)
|
|
||||||
|
|
||||||
// eslint-disable-next-line no-eval
|
|
||||||
module.exports = eval('"undefined" !== typeof require ? require : undefined');
|
|
|
@ -1,93 +0,0 @@
|
||||||
const babelmerge = require('babel-merge');
|
|
||||||
const globals = require('globals');
|
|
||||||
|
|
||||||
const R = require('../../require');
|
|
||||||
|
|
||||||
module.exports = (flecks) => {
|
|
||||||
const merging = [
|
|
||||||
{
|
|
||||||
plugins: [R.resolve('@babel/plugin-syntax-dynamic-import')],
|
|
||||||
presets: [
|
|
||||||
[
|
|
||||||
R.resolve('@babel/preset-env'),
|
|
||||||
{
|
|
||||||
shippedProposals: true,
|
|
||||||
targets: {
|
|
||||||
esmodules: true,
|
|
||||||
node: 'current',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
],
|
|
||||||
},
|
|
||||||
];
|
|
||||||
if (flecks) {
|
|
||||||
merging.push({configFile: flecks.buildConfig('babel.config.js')});
|
|
||||||
const flecksBabelConfig = flecks.babel();
|
|
||||||
merging.push(...flecksBabelConfig.map(([, babel]) => babel));
|
|
||||||
}
|
|
||||||
const babelConfig = babelmerge.all(merging);
|
|
||||||
return {
|
|
||||||
extends: [
|
|
||||||
R.resolve('eslint-config-airbnb'),
|
|
||||||
R.resolve('eslint-config-airbnb/hooks'),
|
|
||||||
],
|
|
||||||
globals: {
|
|
||||||
...globals.browser,
|
|
||||||
...globals.es2021,
|
|
||||||
...globals.mocha,
|
|
||||||
...globals.node,
|
|
||||||
__non_webpack_require__: true,
|
|
||||||
},
|
|
||||||
ignorePatterns: [
|
|
||||||
'dist/**',
|
|
||||||
// Not even gonna try.
|
|
||||||
'build/dox/hooks.js',
|
|
||||||
],
|
|
||||||
overrides: [
|
|
||||||
{
|
|
||||||
files: [
|
|
||||||
'test/**/*.js',
|
|
||||||
],
|
|
||||||
rules: {
|
|
||||||
'brace-style': 'off',
|
|
||||||
'class-methods-use-this': 'off',
|
|
||||||
'import/no-extraneous-dependencies': 'off',
|
|
||||||
'import/no-unresolved': 'off',
|
|
||||||
'max-classes-per-file': 'off',
|
|
||||||
'no-new': 'off',
|
|
||||||
'no-unused-expressions': 'off',
|
|
||||||
'padded-blocks': 'off',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
parser: R.resolve('@babel/eslint-parser'),
|
|
||||||
parserOptions: {
|
|
||||||
requireConfigFile: false,
|
|
||||||
babelOptions: babelConfig,
|
|
||||||
},
|
|
||||||
plugins: ['@babel'],
|
|
||||||
rules: {
|
|
||||||
'brace-style': ['error', 'stroustrup'],
|
|
||||||
// Bug: https://github.com/import-js/eslint-plugin-import/issues/2181
|
|
||||||
'import/no-import-module-exports': 'off',
|
|
||||||
'import/prefer-default-export': 'off',
|
|
||||||
'jsx-a11y/control-has-associated-label': ['error', {assert: 'either'}],
|
|
||||||
'jsx-a11y/label-has-associated-control': ['error', {assert: 'either'}],
|
|
||||||
'no-param-reassign': ['error', {props: false}],
|
|
||||||
'no-plusplus': 'off',
|
|
||||||
'no-shadow': 'off',
|
|
||||||
'object-curly-spacing': 'off',
|
|
||||||
'padded-blocks': ['error', {classes: 'always'}],
|
|
||||||
yoda: 'off',
|
|
||||||
},
|
|
||||||
settings: {
|
|
||||||
'import/resolver': {
|
|
||||||
node: {},
|
|
||||||
},
|
|
||||||
react: {
|
|
||||||
version: '18.2.0',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
};
|
|
|
@ -1,65 +0,0 @@
|
||||||
const {spawnSync} = require('child_process');
|
|
||||||
const {
|
|
||||||
mkdirSync,
|
|
||||||
readFileSync,
|
|
||||||
statSync,
|
|
||||||
writeFileSync,
|
|
||||||
} = require('fs');
|
|
||||||
const {join} = require('path');
|
|
||||||
|
|
||||||
const D = require('../../debug');
|
|
||||||
const {default: Flecks} = require('../flecks');
|
|
||||||
|
|
||||||
const debug = D('@flecks/core/server/build/eslint.config.js');
|
|
||||||
|
|
||||||
const {
|
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
|
||||||
FLECKS_CORE_SYNC_FOR_ESLINT = false,
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
// This is kinda nuts, but ESLint doesn't support its configuration files returning a promise!
|
|
||||||
if (FLECKS_CORE_SYNC_FOR_ESLINT) {
|
|
||||||
(async () => {
|
|
||||||
debug('bootstrapping flecks...');
|
|
||||||
const flecks = Flecks.bootstrap();
|
|
||||||
debug('bootstrapped');
|
|
||||||
const eslintConfigFn = __non_webpack_require__(flecks.buildConfig('default.eslint.config.js'));
|
|
||||||
const eslintConfig = await eslintConfigFn(flecks);
|
|
||||||
const webpackConfigFn = __non_webpack_require__(flecks.buildConfig('webpack.config.js', 'fleck'));
|
|
||||||
const webpackConfig = await webpackConfigFn({}, {mode: 'development'}, flecks);
|
|
||||||
eslintConfig.settings['import/resolver'].webpack = {
|
|
||||||
config: {
|
|
||||||
resolve: webpackConfig.resolve,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
process.stdout.write(JSON.stringify(eslintConfig, null, 2));
|
|
||||||
})();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
const cacheDirectory = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'core');
|
|
||||||
try {
|
|
||||||
statSync(join(cacheDirectory, 'eslint.config.json'));
|
|
||||||
module.exports = JSON.parse(readFileSync(join(cacheDirectory, 'eslint.config.json')).toString());
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
// Just silly. By synchronously spawning... ourselves, the spawned copy can use async.
|
|
||||||
const {stderr, stdout} = spawnSync('node', [__filename], {
|
|
||||||
env: {
|
|
||||||
FLECKS_CORE_SYNC_FOR_ESLINT: true,
|
|
||||||
NODE_PATH: join(FLECKS_CORE_ROOT, 'node_modules'),
|
|
||||||
...process.env,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
// eslint-disable-next-line no-console
|
|
||||||
console.error(stderr.toString());
|
|
||||||
const json = stdout.toString();
|
|
||||||
try {
|
|
||||||
statSync(join(FLECKS_CORE_ROOT, 'node_modules'));
|
|
||||||
mkdirSync(cacheDirectory, {recursive: true});
|
|
||||||
writeFileSync(join(cacheDirectory, 'eslint.config.json'), json);
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line no-empty
|
|
||||||
catch (error) {}
|
|
||||||
module.exports = JSON.parse(json);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,94 +0,0 @@
|
||||||
/* eslint-disable import/first */
|
|
||||||
import 'source-map-support/register';
|
|
||||||
|
|
||||||
if ('production' !== process.env.NODE_ENV) {
|
|
||||||
try {
|
|
||||||
// eslint-disable-next-line global-require, import/no-unresolved
|
|
||||||
__non_webpack_require__('dotenv/config');
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line no-empty
|
|
||||||
catch (error) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
import intersectionBy from 'lodash.intersectionby';
|
|
||||||
|
|
||||||
import D from '../../debug';
|
|
||||||
import Flecks from '../flecks';
|
|
||||||
|
|
||||||
const debug = D('@flecks/core/server/build/fleckspack.config.js');
|
|
||||||
|
|
||||||
const {
|
|
||||||
FLECKS_CORE_BUILD_LIST = '',
|
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
const buildList = FLECKS_CORE_BUILD_LIST
|
|
||||||
.split(',')
|
|
||||||
.map((name) => name.trim())
|
|
||||||
.filter((e) => e);
|
|
||||||
|
|
||||||
export default async (env, argv) => {
|
|
||||||
debug('bootstrapping flecks...');
|
|
||||||
const flecks = Flecks.bootstrap();
|
|
||||||
debug('bootstrapped');
|
|
||||||
|
|
||||||
debug('gathering configs');
|
|
||||||
const targets = [];
|
|
||||||
Object.entries(flecks.invoke('@flecks/core.targets'))
|
|
||||||
.forEach(([fleck, fleckTargets]) => {
|
|
||||||
intersectionBy(fleckTargets, buildList.length ? buildList : fleckTargets)
|
|
||||||
.forEach((target) => {
|
|
||||||
targets.push([target, fleck]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
debug('building: %O', targets.map(([target]) => target));
|
|
||||||
if (0 === targets.length) {
|
|
||||||
debug('no build configuration found! aborting...');
|
|
||||||
await new Promise(() => {});
|
|
||||||
}
|
|
||||||
const entries = await Promise.all(targets.map(
|
|
||||||
async ([target, fleck]) => {
|
|
||||||
const buildConfig = flecks.resolveBuildConfig(
|
|
||||||
[
|
|
||||||
FLECKS_CORE_ROOT,
|
|
||||||
flecks.resolvePath(fleck),
|
|
||||||
],
|
|
||||||
[
|
|
||||||
`${target}.webpack.config.js`,
|
|
||||||
'webpack.config.js',
|
|
||||||
],
|
|
||||||
);
|
|
||||||
const configFn = __non_webpack_require__(buildConfig);
|
|
||||||
if ('function' !== typeof configFn) {
|
|
||||||
debug(`'${
|
|
||||||
target
|
|
||||||
}' build configuration expected function got ${
|
|
||||||
typeof configFn
|
|
||||||
}! aborting...`);
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
return [target, await configFn(env, argv, flecks)];
|
|
||||||
},
|
|
||||||
));
|
|
||||||
await Promise.all(
|
|
||||||
entries.map(async ([target, config]) => (
|
|
||||||
flecks.invokeFlat('@flecks/core.build', target, config, env, argv)
|
|
||||||
)),
|
|
||||||
);
|
|
||||||
const webpackConfigs = Object.fromEntries(entries);
|
|
||||||
await Promise.all(flecks.invokeFlat('@flecks/core.build.alter', webpackConfigs, env, argv));
|
|
||||||
const enterableWebpackConfigs = Object.values(webpackConfigs)
|
|
||||||
.filter((webpackConfig) => {
|
|
||||||
if (!webpackConfig.entry) {
|
|
||||||
debug('webpack configurations %O had no entry... discarding', webpackConfig);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
if (0 === enterableWebpackConfigs.length) {
|
|
||||||
debug('no webpack configuration found! aborting...');
|
|
||||||
await new Promise(() => {});
|
|
||||||
}
|
|
||||||
debug('webpack configurations %O', enterableWebpackConfigs);
|
|
||||||
return enterableWebpackConfigs;
|
|
||||||
};
|
|
|
@ -1,163 +0,0 @@
|
||||||
import {statSync} from 'fs';
|
|
||||||
import {dirname, sep} from 'path';
|
|
||||||
|
|
||||||
import {
|
|
||||||
getEnv,
|
|
||||||
OptionManager,
|
|
||||||
transformSync,
|
|
||||||
version,
|
|
||||||
} from '@babel/core';
|
|
||||||
import sourceMapSupport from 'source-map-support';
|
|
||||||
|
|
||||||
sourceMapSupport.install();
|
|
||||||
|
|
||||||
const cache = require('@babel/register/lib/cache');
|
|
||||||
|
|
||||||
const identity = (i) => i;
|
|
||||||
|
|
||||||
// This is basically what @babel/register does, but better in several ways.
|
|
||||||
class Compiler {
|
|
||||||
|
|
||||||
constructor(options) {
|
|
||||||
// Make some goodies exist in nodespace.
|
|
||||||
this.options = {
|
|
||||||
...options,
|
|
||||||
plugins: [
|
|
||||||
...(options.plugins || []),
|
|
||||||
...this.constructor.nodespaceBabelPlugins(),
|
|
||||||
],
|
|
||||||
};
|
|
||||||
this.constructor.warmUpCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
compile(input, request) {
|
|
||||||
const options = new OptionManager()
|
|
||||||
.init({
|
|
||||||
sourceRoot: `${dirname(request)}${sep}`,
|
|
||||||
...this.options,
|
|
||||||
filename: request,
|
|
||||||
});
|
|
||||||
if (null === options) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
const {cached, store} = this.lookup(options, request);
|
|
||||||
if (cached) {
|
|
||||||
return cached;
|
|
||||||
}
|
|
||||||
const {code, map} = transformSync(input, {
|
|
||||||
...options,
|
|
||||||
sourceMaps: 'both',
|
|
||||||
ast: false,
|
|
||||||
});
|
|
||||||
this.constructor.maps[request] = map;
|
|
||||||
return store({code, map});
|
|
||||||
}
|
|
||||||
|
|
||||||
static installSourceMapSupport() {
|
|
||||||
this.maps = Object.create(null);
|
|
||||||
sourceMapSupport.install({
|
|
||||||
handleUncaughtExceptions: false,
|
|
||||||
environment: 'node',
|
|
||||||
retrieveSourceMap: (request) => {
|
|
||||||
const map = this.maps[request];
|
|
||||||
if (map) {
|
|
||||||
return {url: null, map};
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
lookup(options, request) {
|
|
||||||
if (!this.constructor.cache) {
|
|
||||||
return {
|
|
||||||
cached: null,
|
|
||||||
store: identity,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
let cacheKey = `${JSON.stringify(options)}:${version}`;
|
|
||||||
const env = getEnv();
|
|
||||||
if (env) {
|
|
||||||
cacheKey += `:${env}`;
|
|
||||||
}
|
|
||||||
const cached = this.constructor.cache[cacheKey];
|
|
||||||
const mtime = +statSync(request).mtime;
|
|
||||||
if (cached && cached.mtime === mtime) {
|
|
||||||
return {
|
|
||||||
cached: cached.value,
|
|
||||||
store: identity,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
return {
|
|
||||||
cached: null,
|
|
||||||
store: (value) => {
|
|
||||||
this.constructor.cache[cacheKey] = {mtime, value};
|
|
||||||
cache.setDirty();
|
|
||||||
return value;
|
|
||||||
},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static nodespaceBabelPlugins() {
|
|
||||||
return [
|
|
||||||
[
|
|
||||||
'prepend',
|
|
||||||
{
|
|
||||||
prepend: [
|
|
||||||
'require.context = (',
|
|
||||||
' directory,',
|
|
||||||
' useSubdirectories = true,',
|
|
||||||
' regExp = /^\\.\\/.*$/,',
|
|
||||||
' mode = "sync",',
|
|
||||||
') => {',
|
|
||||||
' const glob = require("glob");',
|
|
||||||
' const {join} = require("path");',
|
|
||||||
' const {resolve, sep} = require("path");',
|
|
||||||
' const keys = glob.sync(',
|
|
||||||
' useSubdirectories ? "**/*" : "*",',
|
|
||||||
' {cwd: resolve(__dirname, directory)},',
|
|
||||||
' )',
|
|
||||||
' .filter((key) => key.match(regExp))',
|
|
||||||
' .map(',
|
|
||||||
' (key) => (',
|
|
||||||
' -1 !== [".".charCodeAt(0), "/".charCodeAt(0)].indexOf(key.charCodeAt(0))',
|
|
||||||
' ? key',
|
|
||||||
' : ("." + sep + key)',
|
|
||||||
' ),',
|
|
||||||
' );',
|
|
||||||
' const R = (request) => {',
|
|
||||||
' if (-1 === keys.indexOf(request)) {',
|
|
||||||
// eslint-disable-next-line no-template-curly-in-string
|
|
||||||
' throw new Error(`Cannot find module \'${request}\'`);',
|
|
||||||
' }',
|
|
||||||
' return require(join(__dirname, directory, request));',
|
|
||||||
' };',
|
|
||||||
' R.id = __filename',
|
|
||||||
' R.keys = () => keys;',
|
|
||||||
' return R;',
|
|
||||||
'};',
|
|
||||||
].join('\n'),
|
|
||||||
},
|
|
||||||
'require.context',
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'prepend',
|
|
||||||
{
|
|
||||||
prepend: '"undefined" === typeof global.__non_webpack_require__ && (global.__non_webpack_require__ = require);',
|
|
||||||
},
|
|
||||||
'__non_webpack_require__',
|
|
||||||
],
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
static warmUpCache() {
|
|
||||||
if ('undefined' === typeof this.cache) {
|
|
||||||
cache.load();
|
|
||||||
this.cache = cache.get();
|
|
||||||
this.installSourceMapSupport();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default Compiler;
|
|
|
@ -1,733 +0,0 @@
|
||||||
import {
|
|
||||||
readFileSync,
|
|
||||||
realpathSync,
|
|
||||||
statSync,
|
|
||||||
} from 'fs';
|
|
||||||
import {readFile, writeFile} from 'fs/promises';
|
|
||||||
import {
|
|
||||||
basename,
|
|
||||||
dirname,
|
|
||||||
extname,
|
|
||||||
isAbsolute,
|
|
||||||
join,
|
|
||||||
resolve,
|
|
||||||
sep,
|
|
||||||
} from 'path';
|
|
||||||
|
|
||||||
import babelmerge from 'babel-merge';
|
|
||||||
import enhancedResolve from 'enhanced-resolve';
|
|
||||||
import {dump as dumpYml, load as loadYml} from 'js-yaml';
|
|
||||||
import {addHook} from 'pirates';
|
|
||||||
|
|
||||||
import D from '../debug';
|
|
||||||
import Flecks from '../flecks';
|
|
||||||
import R from '../require';
|
|
||||||
import Compiler from './compiler';
|
|
||||||
|
|
||||||
const {
|
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
|
||||||
FLECKS_YML = 'flecks.yml',
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
const debug = D('@flecks/core/flecks/server');
|
|
||||||
const debugSilly = debug.extend('silly');
|
|
||||||
|
|
||||||
export default class ServerFlecks extends Flecks {
|
|
||||||
|
|
||||||
constructor(options = {}) {
|
|
||||||
super(options);
|
|
||||||
this.overrideConfigFromEnvironment();
|
|
||||||
this.buildConfigs = {};
|
|
||||||
this.loadBuildConfigs();
|
|
||||||
this.flecksConfig = options.flecksConfig || {};
|
|
||||||
this.resolver = options.resolver || {};
|
|
||||||
}
|
|
||||||
|
|
||||||
static async addFleckToYml(fleck, path) {
|
|
||||||
const key = [fleck].concat(path ? `.${sep}${join('packages', path, 'src')}` : []).join(':');
|
|
||||||
const ymlPath = join(FLECKS_CORE_ROOT, 'build', 'flecks.yml');
|
|
||||||
let yml = loadYml(await readFile(ymlPath));
|
|
||||||
yml = Object.fromEntries(Object.entries(yml).concat([[key, {}]]));
|
|
||||||
await writeFile(ymlPath, dumpYml(yml, {sortKeys: true}));
|
|
||||||
}
|
|
||||||
|
|
||||||
get aliasedConfig() {
|
|
||||||
const aliases = this.aliases();
|
|
||||||
return Object.fromEntries(
|
|
||||||
Object.entries(
|
|
||||||
this.config,
|
|
||||||
)
|
|
||||||
.map(([path, config]) => [
|
|
||||||
this.fleckIsAliased(path) ? `${path}:${aliases[path]}` : path,
|
|
||||||
config,
|
|
||||||
]),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
aliases() {
|
|
||||||
return this.constructor.aliases(this.flecksConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
static aliases(flecksConfig) {
|
|
||||||
const keys = Object.keys(flecksConfig);
|
|
||||||
let aliases = {};
|
|
||||||
for (let i = 0; i < keys.length; ++i) {
|
|
||||||
const key = keys[i];
|
|
||||||
const config = flecksConfig[key];
|
|
||||||
if (config.aliases && Object.keys(config.aliases).length > 0) {
|
|
||||||
aliases = {...aliases, ...config.aliases};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return aliases;
|
|
||||||
}
|
|
||||||
|
|
||||||
babel() {
|
|
||||||
return this.constructor.babel(this.flecksConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
static babel(flecksConfig) {
|
|
||||||
return Object.entries(flecksConfig)
|
|
||||||
.filter(([, {babel}]) => babel)
|
|
||||||
.map(([key, {babel}]) => [key, babel]);
|
|
||||||
}
|
|
||||||
|
|
||||||
static bootstrap(
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
platforms = ['server'],
|
|
||||||
root = FLECKS_CORE_ROOT,
|
|
||||||
} = {},
|
|
||||||
) {
|
|
||||||
// Load or use parameterized configuration.
|
|
||||||
let configType;
|
|
||||||
if (!config) {
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
[configType, config] = this.loadConfig(root);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
configType = 'parameter';
|
|
||||||
}
|
|
||||||
debug('bootstrap configuration (%s)', configType);
|
|
||||||
debugSilly(config);
|
|
||||||
// Make resolver and load flecksConfig.
|
|
||||||
const {flecksConfig, resolver} = this.makeResolverAndLoadRcs(
|
|
||||||
Object.keys(config),
|
|
||||||
platforms,
|
|
||||||
root,
|
|
||||||
);
|
|
||||||
// Rewrite aliased config keys.
|
|
||||||
// eslint-disable-next-line no-param-reassign
|
|
||||||
config = Object.fromEntries(
|
|
||||||
Object.entries(config)
|
|
||||||
.map(([key, value]) => {
|
|
||||||
const index = key.indexOf(':');
|
|
||||||
return [-1 !== index ? key.slice(0, index) : key, value];
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
this.installCompilers(flecksConfig, resolver);
|
|
||||||
// Instantiate with mixins.
|
|
||||||
return ServerFlecks.from({
|
|
||||||
config,
|
|
||||||
flecks: Object.fromEntries(
|
|
||||||
Object.keys(resolver)
|
|
||||||
.map((path) => [path, R(this.resolve(resolver, path))]),
|
|
||||||
),
|
|
||||||
platforms,
|
|
||||||
flecksConfig,
|
|
||||||
resolver,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
buildConfig(path, specific) {
|
|
||||||
const config = this.buildConfigs[path];
|
|
||||||
if (!config) {
|
|
||||||
throw new Error(`Unknown build config '${path}'`);
|
|
||||||
}
|
|
||||||
const paths = [];
|
|
||||||
if (specific) {
|
|
||||||
if ('specifier' in config) {
|
|
||||||
if (false === config.specifier) {
|
|
||||||
paths.shift();
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
paths.push(config.specifier(specific));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
paths.push(`${specific}.${path}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
paths.push(path);
|
|
||||||
const roots = [config.root];
|
|
||||||
if (config.root !== FLECKS_CORE_ROOT) {
|
|
||||||
roots.push(FLECKS_CORE_ROOT);
|
|
||||||
}
|
|
||||||
roots.push(this.resolvePath(this.resolve(config.fleck)));
|
|
||||||
return this.constructor.resolveBuildConfig(this.resolver, roots, paths);
|
|
||||||
}
|
|
||||||
|
|
||||||
static environmentalize(path) {
|
|
||||||
return path
|
|
||||||
// - `@flecks/core` -> `flecks_core`
|
|
||||||
.replace(/[^a-zA-Z0-9]/g, '_')
|
|
||||||
.replace(/_*(.*)_*/, '$1');
|
|
||||||
}
|
|
||||||
|
|
||||||
exts() {
|
|
||||||
return this.constructor.exts(this.flecksConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
static exts(flecksConfig) {
|
|
||||||
const keys = Object.keys(flecksConfig);
|
|
||||||
const exts = [];
|
|
||||||
for (let i = 0; i < keys.length; ++i) {
|
|
||||||
const key = keys[i];
|
|
||||||
const config = flecksConfig[key];
|
|
||||||
if (config.exts) {
|
|
||||||
exts.push(...config.exts);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return exts;
|
|
||||||
}
|
|
||||||
|
|
||||||
fleckIsAliased(fleck) {
|
|
||||||
return this.constructor.fleckIsAliased(this.resolver, fleck);
|
|
||||||
}
|
|
||||||
|
|
||||||
static fleckIsAliased(resolver, fleck) {
|
|
||||||
return fleck !== this.resolve(resolver, fleck);
|
|
||||||
}
|
|
||||||
|
|
||||||
fleckIsCompiled(fleck) {
|
|
||||||
return this.constructor.fleckIsCompiled(this.resolver, fleck);
|
|
||||||
}
|
|
||||||
|
|
||||||
static fleckIsCompiled(resolver, fleck) {
|
|
||||||
return this.fleckIsAliased(resolver, fleck) || this.fleckIsSymlinked(resolver, fleck);
|
|
||||||
}
|
|
||||||
|
|
||||||
fleckIsSymlinked(fleck) {
|
|
||||||
return this.constructor.fleckIsSymlinked(this.resolver, fleck);
|
|
||||||
}
|
|
||||||
|
|
||||||
static fleckIsSymlinked(resolver, fleck) {
|
|
||||||
const resolved = R.resolve(this.resolve(resolver, fleck));
|
|
||||||
const realpath = realpathSync(resolved);
|
|
||||||
return realpath !== resolved;
|
|
||||||
}
|
|
||||||
|
|
||||||
static installCompilers(flecksConfig, resolver) {
|
|
||||||
const paths = Object.keys(resolver);
|
|
||||||
debugSilly('flecksConfig: %O', flecksConfig);
|
|
||||||
// Merge aliases;
|
|
||||||
const aliases = Object.fromEntries(
|
|
||||||
Object.entries({
|
|
||||||
// from fleck configuration above,
|
|
||||||
...Object.fromEntries(Object.entries(resolver).filter(([from, to]) => from !== to)),
|
|
||||||
// from symlinks,
|
|
||||||
...(
|
|
||||||
Object.fromEntries(
|
|
||||||
paths.filter((path) => this.fleckIsSymlinked(resolver, path))
|
|
||||||
.map((path) => [path, this.sourcepath(R.resolve(this.resolve(resolver, path)))]),
|
|
||||||
)
|
|
||||||
),
|
|
||||||
// and from RCs.
|
|
||||||
...this.aliases(flecksConfig),
|
|
||||||
})
|
|
||||||
.map(([from, to]) => [from, to.endsWith('/index') ? to.slice(0, -6) : to]),
|
|
||||||
);
|
|
||||||
if (Object.keys(aliases).length > 0) {
|
|
||||||
debugSilly('aliases: %O', aliases);
|
|
||||||
}
|
|
||||||
const exts = this.exts(flecksConfig);
|
|
||||||
const enhancedResolver = enhancedResolve.create.sync({
|
|
||||||
extensions: exts,
|
|
||||||
alias: aliases,
|
|
||||||
});
|
|
||||||
// Stub server-unfriendly modules.
|
|
||||||
const stubs = this.stubs(['server'], flecksConfig);
|
|
||||||
if (stubs.length > 0) {
|
|
||||||
debugSilly('stubbing: %O', stubs);
|
|
||||||
}
|
|
||||||
// Do we need to get up in `require()`'s guts?
|
|
||||||
if (
|
|
||||||
Object.keys(aliases).length > 0
|
|
||||||
|| stubs.length > 0
|
|
||||||
) {
|
|
||||||
const {Module} = R('module');
|
|
||||||
const {require: Mr} = Module.prototype;
|
|
||||||
const aliasKeys = Object.keys(aliases);
|
|
||||||
Module.prototype.require = function hackedRequire(request, options) {
|
|
||||||
for (let i = 0; i < stubs.length; ++i) {
|
|
||||||
if (request.match(stubs[i])) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (aliasKeys.find((aliasKey) => request.startsWith(aliasKey))) {
|
|
||||||
try {
|
|
||||||
const resolved = enhancedResolver(FLECKS_CORE_ROOT, request);
|
|
||||||
if (resolved) {
|
|
||||||
return Mr.call(this, resolved, options);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line no-empty
|
|
||||||
catch (error) {}
|
|
||||||
}
|
|
||||||
return Mr.call(this, request, options);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// Compile.
|
|
||||||
const compilations = [];
|
|
||||||
const needCompilation = paths
|
|
||||||
.filter((path) => this.fleckIsCompiled(resolver, path));
|
|
||||||
if (needCompilation.length > 0) {
|
|
||||||
// Augment the compilations with babel config from flecksrc.
|
|
||||||
const flecksBabelConfig = babelmerge.all(this.babel(flecksConfig).map(([, babel]) => babel));
|
|
||||||
debugSilly('.flecksrc: babel: %O', flecksBabelConfig);
|
|
||||||
// Key flecks needing compilation by their roots, so we can compile all common roots with a
|
|
||||||
// single invocation of `@babel/register`.
|
|
||||||
const compilationRootMap = {};
|
|
||||||
needCompilation.forEach((fleck) => {
|
|
||||||
const root = this.root(resolver, fleck);
|
|
||||||
if (!compilationRootMap[root]) {
|
|
||||||
compilationRootMap[root] = [];
|
|
||||||
}
|
|
||||||
compilationRootMap[root].push(fleck);
|
|
||||||
});
|
|
||||||
// Register a compilation for each root.
|
|
||||||
Object.entries(compilationRootMap).forEach(([root, compiling]) => {
|
|
||||||
const resolved = dirname(R.resolve(join(root, 'package.json')));
|
|
||||||
const sourcepath = this.sourcepath(resolved);
|
|
||||||
const sourceroot = join(sourcepath, '..');
|
|
||||||
// Load babel config from whichever we find first:
|
|
||||||
// - The fleck being compiled's build directory
|
|
||||||
// - The root build directory
|
|
||||||
// - Finally, the built-in babel config
|
|
||||||
let builtInPath;
|
|
||||||
try {
|
|
||||||
builtInPath = this.resolvePath(resolver, '@flecks/core/server');
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
// This file won't be resolved during testing.
|
|
||||||
builtInPath = join(__dirname, '..', 'src', 'server');
|
|
||||||
}
|
|
||||||
const configFile = this.resolveBuildConfig(
|
|
||||||
resolver,
|
|
||||||
[
|
|
||||||
resolved,
|
|
||||||
FLECKS_CORE_ROOT,
|
|
||||||
builtInPath,
|
|
||||||
],
|
|
||||||
[
|
|
||||||
'babel.config.js',
|
|
||||||
],
|
|
||||||
);
|
|
||||||
const ignore = `${resolve(join(sourceroot, 'node_modules'))}/`;
|
|
||||||
const only = `${resolve(sourceroot)}/`;
|
|
||||||
const config = {
|
|
||||||
// Augment the selected config with the babel config from RCs.
|
|
||||||
configFile,
|
|
||||||
// Target the compiler to avoid unnecessary work.
|
|
||||||
ignore: [ignore],
|
|
||||||
only: [only],
|
|
||||||
};
|
|
||||||
debugSilly('compiling %O with %j at %s', compiling, config, only);
|
|
||||||
compilations.push({
|
|
||||||
ignore,
|
|
||||||
only,
|
|
||||||
compiler: new Compiler(babelmerge(config, flecksBabelConfig)),
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const findCompiler = (request) => {
|
|
||||||
for (let i = 0; i < compilations.length; ++i) {
|
|
||||||
const {compiler, ignore, only} = compilations[i];
|
|
||||||
if (request.startsWith(only) && !request.startsWith(ignore)) {
|
|
||||||
return compiler;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
};
|
|
||||||
debugSilly('pirating exts: %O', exts);
|
|
||||||
addHook(
|
|
||||||
(code, request) => {
|
|
||||||
const compilation = findCompiler(request).compile(code, request);
|
|
||||||
return null === compilation ? code : compilation.code;
|
|
||||||
},
|
|
||||||
{exts, matcher: (request) => !!findCompiler(request)},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
loadBuildConfigs() {
|
|
||||||
Object.entries(this.invoke('@flecks/core.build.config'))
|
|
||||||
.forEach(([fleck, configs]) => {
|
|
||||||
configs.forEach((config) => {
|
|
||||||
const defaults = {
|
|
||||||
fleck,
|
|
||||||
};
|
|
||||||
if (Array.isArray(config)) {
|
|
||||||
this.registerBuildConfig(config[0], {...defaults, ...config[1]});
|
|
||||||
}
|
|
||||||
this.registerBuildConfig(config, defaults);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static loadConfig(root) {
|
|
||||||
const resolvedRoot = resolve(FLECKS_CORE_ROOT, root);
|
|
||||||
try {
|
|
||||||
const {load} = R('js-yaml');
|
|
||||||
const filename = join(resolvedRoot, 'build', FLECKS_YML);
|
|
||||||
const buffer = readFileSync(filename, 'utf8');
|
|
||||||
debugSilly('parsing configuration from YML...');
|
|
||||||
return ['YML', load(buffer, {filename}) || {}];
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
if ('ENOENT' !== error.code) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
return ['barebones', {'@flecks/core': {}, '@flecks/fleck': {}}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static makeResolver(maybeAliasedPath, platforms, root) {
|
|
||||||
const resolvedRoot = resolve(FLECKS_CORE_ROOT, root);
|
|
||||||
const resolver = {};
|
|
||||||
// `!platform` excludes that platform.
|
|
||||||
const without = platforms
|
|
||||||
.filter((platform) => '!'.charCodeAt(0) === platform.charCodeAt(0))
|
|
||||||
.map((platform) => platform.slice(1));
|
|
||||||
// Parse the alias (if any).
|
|
||||||
const index = maybeAliasedPath.indexOf(':');
|
|
||||||
const [path, alias] = -1 === index
|
|
||||||
? [maybeAliasedPath, undefined]
|
|
||||||
: [maybeAliasedPath.slice(0, index), maybeAliasedPath.slice(index + 1)];
|
|
||||||
// Run it by the exception list.
|
|
||||||
if (-1 !== without.indexOf(path.split('/').pop())) {
|
|
||||||
// eslint-disable-next-line no-continue
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
// Resolve the path (if necessary).
|
|
||||||
let resolvedPath;
|
|
||||||
if (alias) {
|
|
||||||
resolvedPath = isAbsolute(alias) ? alias : join(resolvedRoot, alias);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if (path.startsWith('.')) {
|
|
||||||
throw new Error(`non-aliased relative path '${path}' in configuration`);
|
|
||||||
}
|
|
||||||
resolvedPath = path;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
R.resolve(resolvedPath);
|
|
||||||
resolver[path] = resolvedPath;
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line no-empty
|
|
||||||
catch (error) {}
|
|
||||||
// Discover platform-specific variants.
|
|
||||||
if (platforms) {
|
|
||||||
platforms.forEach((platform) => {
|
|
||||||
try {
|
|
||||||
const resolvedPlatformPath = join(resolvedPath, platform);
|
|
||||||
R.resolve(resolvedPlatformPath);
|
|
||||||
resolver[join(path, platform)] = resolvedPlatformPath;
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line no-empty
|
|
||||||
catch (error) {}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
return resolver;
|
|
||||||
}
|
|
||||||
|
|
||||||
static makeResolverAndLoadRcs(
|
|
||||||
maybeAliasedPaths,
|
|
||||||
platforms = ['server'],
|
|
||||||
root = FLECKS_CORE_ROOT,
|
|
||||||
) {
|
|
||||||
const resolver = {};
|
|
||||||
const rootsFrom = (paths) => (
|
|
||||||
Array.from(new Set(
|
|
||||||
paths
|
|
||||||
.map((path) => this.root(resolver, path))
|
|
||||||
.filter((e) => !!e),
|
|
||||||
))
|
|
||||||
);
|
|
||||||
for (let i = 0; i < maybeAliasedPaths.length; ++i) {
|
|
||||||
const maybeAliasedPath = maybeAliasedPaths[i];
|
|
||||||
Object.entries(this.makeResolver(maybeAliasedPath, platforms, root))
|
|
||||||
.forEach(([path, alias]) => {
|
|
||||||
resolver[path] = alias;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const flecksConfig = {};
|
|
||||||
const roots = Array.from(new Set(
|
|
||||||
rootsFrom(Object.keys(resolver))
|
|
||||||
.concat(FLECKS_CORE_ROOT),
|
|
||||||
));
|
|
||||||
let rootsToScan = roots;
|
|
||||||
while (rootsToScan.length > 0) {
|
|
||||||
const dependencies = [];
|
|
||||||
for (let i = 0; i < rootsToScan.length; ++i) {
|
|
||||||
const root = rootsToScan[i];
|
|
||||||
try {
|
|
||||||
flecksConfig[root] = R(join(root, 'build', 'flecks.config'));
|
|
||||||
const {dependencies: flecksConfigDependencies = []} = flecksConfig[root];
|
|
||||||
dependencies.push(...flecksConfigDependencies);
|
|
||||||
flecksConfigDependencies.forEach((dependency) => {
|
|
||||||
Object.entries(this.makeResolver(dependency, platforms, root))
|
|
||||||
.forEach(([path, alias]) => {
|
|
||||||
resolver[path] = alias;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
if ('MODULE_NOT_FOUND' !== error.code) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rootsToScan = rootsFrom(dependencies)
|
|
||||||
.filter((root) => !flecksConfig[root]);
|
|
||||||
}
|
|
||||||
return {flecksConfig, resolver};
|
|
||||||
}
|
|
||||||
|
|
||||||
overrideConfigFromEnvironment() {
|
|
||||||
const keys = Object.keys(process.env);
|
|
||||||
const seen = [];
|
|
||||||
Object.keys(this.flecks)
|
|
||||||
.sort((l, r) => (l < r ? 1 : -1))
|
|
||||||
.forEach((fleck) => {
|
|
||||||
const prefix = `FLECKS_ENV__${this.constructor.environmentalize(fleck)}`;
|
|
||||||
keys
|
|
||||||
.filter((key) => key.startsWith(`${prefix}__`) && -1 === seen.indexOf(key))
|
|
||||||
.map((key) => {
|
|
||||||
seen.push(key);
|
|
||||||
debug('reading environment from %s...', key);
|
|
||||||
return [key, process.env[key]];
|
|
||||||
})
|
|
||||||
.map(([key, value]) => [key.slice(prefix.length + 2), value])
|
|
||||||
.map(([subkey, value]) => [subkey.split('_'), value])
|
|
||||||
.forEach(([path, jsonOrString]) => {
|
|
||||||
try {
|
|
||||||
this.set([fleck, ...path], JSON.parse(jsonOrString));
|
|
||||||
debug('read (%s) as JSON', jsonOrString);
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
this.set([fleck, ...path], jsonOrString);
|
|
||||||
debug('read (%s) as string', jsonOrString);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
flecksConfig() {
|
|
||||||
return this.flecksConfig;
|
|
||||||
}
|
|
||||||
|
|
||||||
registerBuildConfig(filename, config) {
|
|
||||||
const defaults = {
|
|
||||||
root: FLECKS_CORE_ROOT,
|
|
||||||
};
|
|
||||||
this.buildConfigs[filename] = {...defaults, ...config};
|
|
||||||
}
|
|
||||||
|
|
||||||
registerResolver(from, to = from) {
|
|
||||||
this.resolver[from] = to;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolve(path) {
|
|
||||||
return this.constructor.resolve(this.resolver, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static resolve(resolver, fleck) {
|
|
||||||
return resolver[fleck] || fleck;
|
|
||||||
}
|
|
||||||
|
|
||||||
resolveBuildConfig(roots, paths) {
|
|
||||||
return this.constructor.resolveBuildConfig(this.resolver, roots, paths);
|
|
||||||
}
|
|
||||||
|
|
||||||
static resolveBuildConfig(resolver, roots, paths) {
|
|
||||||
const tried = [];
|
|
||||||
for (let i = 0; i < roots.length; ++i) {
|
|
||||||
const root = roots[i];
|
|
||||||
for (let j = 0; j < paths.length; ++j) {
|
|
||||||
const path = paths[j];
|
|
||||||
const resolved = join(root, 'build', path);
|
|
||||||
try {
|
|
||||||
tried.push(resolved);
|
|
||||||
statSync(resolved);
|
|
||||||
return resolved;
|
|
||||||
}
|
|
||||||
// eslint-disable-next-line no-empty
|
|
||||||
catch (error) {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
throw new Error(`Couldn't resolve build file '${paths.pop()}', tried: ${tried.join(', ')}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
resolvePath(path) {
|
|
||||||
return this.constructor.resolvePath(this.resolver, path);
|
|
||||||
}
|
|
||||||
|
|
||||||
static resolvePath(resolver, path) {
|
|
||||||
const resolved = R.resolve(this.resolve(resolver, path));
|
|
||||||
const ext = extname(resolved);
|
|
||||||
const base = basename(resolved, ext);
|
|
||||||
return join(dirname(resolved), 'index' === base ? '' : base);
|
|
||||||
}
|
|
||||||
|
|
||||||
root(fleck) {
|
|
||||||
return this.constructor.root(this.resolver, fleck);
|
|
||||||
}
|
|
||||||
|
|
||||||
static root(resolver, fleck) {
|
|
||||||
const parts = this.resolve(resolver, fleck).split('/');
|
|
||||||
try {
|
|
||||||
R.resolve(parts.join('/'));
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
try {
|
|
||||||
R.resolve(join(parts.join('/'), 'build', 'flecks.config'));
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (parts.length > 0) {
|
|
||||||
try {
|
|
||||||
R.resolve(join(parts.join('/'), 'package.json'));
|
|
||||||
return parts.join('/');
|
|
||||||
}
|
|
||||||
catch (error) {
|
|
||||||
parts.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
runtimeCompiler(resolver, runtime, config, {allowlist = []} = {}) {
|
|
||||||
// Compile.
|
|
||||||
const needCompilation = Object.entries(resolver)
|
|
||||||
.filter(([fleck]) => this.constructor.fleckIsCompiled(resolver, fleck));
|
|
||||||
if (needCompilation.length > 0) {
|
|
||||||
const flecksBabelConfig = this.babel();
|
|
||||||
debugSilly('flecks.config.js: babel: %O', flecksBabelConfig);
|
|
||||||
// Alias and de-externalize.
|
|
||||||
needCompilation
|
|
||||||
.sort(([l], [r]) => (l < r ? 1 : -1))
|
|
||||||
.forEach(([fleck, resolved]) => {
|
|
||||||
let alias = this.constructor.fleckIsAliased(resolver, fleck)
|
|
||||||
? resolved
|
|
||||||
: this.constructor.sourcepath(R.resolve(this.constructor.resolve(resolver, fleck)));
|
|
||||||
alias = alias.endsWith('/index') ? alias.slice(0, -6) : alias;
|
|
||||||
allowlist.push(fleck);
|
|
||||||
config.resolve.alias[fleck] = alias;
|
|
||||||
debugSilly('%s runtime de-externalized %s, alias: %s', runtime, fleck, alias);
|
|
||||||
});
|
|
||||||
// Set up compilation at each root.
|
|
||||||
const compiledPaths = [];
|
|
||||||
Array.from(new Set(
|
|
||||||
needCompilation
|
|
||||||
.map(([fleck]) => fleck)
|
|
||||||
.map((fleck) => this.constructor.root(resolver, fleck)),
|
|
||||||
))
|
|
||||||
.forEach((root) => {
|
|
||||||
const resolved = dirname(R.resolve(join(root, 'package.json')));
|
|
||||||
const sourcepath = this.constructor.sourcepath(resolved);
|
|
||||||
const sourceroot = join(sourcepath, '..');
|
|
||||||
compiledPaths.push(sourceroot);
|
|
||||||
// @todo Ideally the fleck's 3rd party modules would be externalized.
|
|
||||||
// Alias this compiled fleck's `node_modules` to the root `node_modules`.
|
|
||||||
config.resolve.alias[join(sourceroot, 'node_modules')] = join(FLECKS_CORE_ROOT, 'node_modules');
|
|
||||||
const configFile = this.buildConfig('babel.config.js');
|
|
||||||
debugSilly('compiling: %s with %s', root, configFile);
|
|
||||||
const babel = {
|
|
||||||
configFile,
|
|
||||||
// Augment the compiler with babel config from `flecks.config.js`.
|
|
||||||
...babelmerge.all(flecksBabelConfig.map(([, babel]) => babel)),
|
|
||||||
};
|
|
||||||
config.module.rules.push(
|
|
||||||
{
|
|
||||||
test: /\.(m?jsx?)?$/,
|
|
||||||
include: [sourceroot],
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: R.resolve('babel-loader'),
|
|
||||||
options: {
|
|
||||||
cacheDirectory: true,
|
|
||||||
babelrc: false,
|
|
||||||
configFile: false,
|
|
||||||
...babel,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
|
||||||
const compiledPathsRegex = new RegExp(
|
|
||||||
`(?:${compiledPaths.map((path) => path.replace(/[\\/]/g, '[\\/]')).join('|')})`,
|
|
||||||
);
|
|
||||||
if (!config.optimization) {
|
|
||||||
config.optimization = {};
|
|
||||||
}
|
|
||||||
if (!config.optimization.splitChunks) {
|
|
||||||
config.optimization.splitChunks = {};
|
|
||||||
}
|
|
||||||
if (!config.optimization.splitChunks.cacheGroups) {
|
|
||||||
config.optimization.splitChunks.cacheGroups = {};
|
|
||||||
}
|
|
||||||
config.optimization.splitChunks.cacheGroups.flecksCompiled = {
|
|
||||||
chunks: 'all',
|
|
||||||
enforce: true,
|
|
||||||
priority: 100,
|
|
||||||
test: compiledPathsRegex,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sourcepath(fleck) {
|
|
||||||
return this.constructor.sourcepath(fleck);
|
|
||||||
}
|
|
||||||
|
|
||||||
static sourcepath(path) {
|
|
||||||
let sourcepath = realpathSync(path);
|
|
||||||
const parts = sourcepath.split('/');
|
|
||||||
const indexOf = parts.lastIndexOf('dist');
|
|
||||||
if (-1 !== indexOf) {
|
|
||||||
parts.splice(indexOf, 1, 'src');
|
|
||||||
sourcepath = parts.join('/');
|
|
||||||
sourcepath = join(dirname(sourcepath), basename(sourcepath, extname(sourcepath)));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
sourcepath = join(sourcepath, 'src');
|
|
||||||
}
|
|
||||||
return sourcepath;
|
|
||||||
}
|
|
||||||
|
|
||||||
stubs() {
|
|
||||||
return this.constructor.stubs(this.platforms, this.flecksConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
static stubs(platforms, flecksConfig) {
|
|
||||||
const keys = Object.keys(flecksConfig);
|
|
||||||
const stubs = [];
|
|
||||||
for (let i = 0; i < keys.length; ++i) {
|
|
||||||
const key = keys[i];
|
|
||||||
const config = flecksConfig[key];
|
|
||||||
if (config.stubs) {
|
|
||||||
Object.entries(config.stubs)
|
|
||||||
.forEach(([platform, patterns]) => {
|
|
||||||
if (-1 !== platforms.indexOf(platform)) {
|
|
||||||
patterns.forEach((pattern) => {
|
|
||||||
stubs.push(pattern);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return stubs;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,14 +1,7 @@
|
||||||
import {join} from 'path';
|
|
||||||
import {inspect} from 'util';
|
import {inspect} from 'util';
|
||||||
|
|
||||||
import webpack from 'webpack';
|
import webpack from 'webpack';
|
||||||
|
|
||||||
import commands from './commands';
|
|
||||||
|
|
||||||
const {
|
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
|
||||||
} = process.env;
|
|
||||||
|
|
||||||
const {defaultOptions} = inspect;
|
const {defaultOptions} = inspect;
|
||||||
defaultOptions.breakLength = 160;
|
defaultOptions.breakLength = 160;
|
||||||
defaultOptions.compact = 6;
|
defaultOptions.compact = 6;
|
||||||
|
@ -17,66 +10,18 @@ defaultOptions.sorted = true;
|
||||||
export {glob} from 'glob';
|
export {glob} from 'glob';
|
||||||
export {dump as dumpYml, load as loadYml} from 'js-yaml';
|
export {dump as dumpYml, load as loadYml} from 'js-yaml';
|
||||||
|
|
||||||
export {
|
export {commands, processCode, spawnWith} from '../../build/commands';
|
||||||
Argument,
|
export {JsonStream, transform} from '../../build/stream';
|
||||||
default as commands,
|
export * from '../../build/webpack';
|
||||||
Option,
|
|
||||||
processCode,
|
|
||||||
program,
|
|
||||||
spawnWith,
|
|
||||||
} from './commands';
|
|
||||||
export {default as Flecks} from './flecks';
|
|
||||||
export {default as require} from '../require';
|
|
||||||
export {JsonStream, transform} from './stream';
|
|
||||||
export * from './webpack';
|
|
||||||
|
|
||||||
export {webpack};
|
export {webpack};
|
||||||
|
|
||||||
export const hooks = {
|
export const hooks = {
|
||||||
'@flecks/core.build': async (target, config, env, argv, flecks) => {
|
'@flecks/web.config': async (req, flecks) => ({
|
||||||
const {
|
'@flecks/core': {
|
||||||
profile,
|
id: flecks.get('@flecks/core.id'),
|
||||||
} = flecks.get('@flecks/core/server');
|
packageManager: undefined,
|
||||||
if (profile.includes(target)) {
|
profile: undefined,
|
||||||
config.plugins.push(
|
|
||||||
new webpack.debug.ProfilingPlugin({
|
|
||||||
outputPath: join(FLECKS_CORE_ROOT, `profile.build-${target}.json`),
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
'@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', {specifier: false}],
|
|
||||||
/**
|
|
||||||
* ESLint configuration. See: https://eslint.org/docs/user-guide/configuring/
|
|
||||||
*/
|
|
||||||
['eslint.config.js', {specifier: false}],
|
|
||||||
/**
|
|
||||||
* Flecks webpack configuration. See: https://webpack.js.org/configuration/
|
|
||||||
*/
|
|
||||||
['fleckspack.config.js', {specifier: false}],
|
|
||||||
/**
|
|
||||||
* Webpack configuration. See: https://webpack.js.org/configuration/
|
|
||||||
*/
|
|
||||||
'webpack.config.js',
|
|
||||||
],
|
|
||||||
'@flecks/core.commands': commands,
|
|
||||||
'@flecks/core.config': () => ({
|
|
||||||
/**
|
|
||||||
* The package manager used for tasks.
|
|
||||||
*/
|
|
||||||
packageManager: 'npm',
|
|
||||||
/**
|
|
||||||
* Build targets to profile with `webpack.debug.ProfilingPlugin`.
|
|
||||||
*/
|
|
||||||
profile: [],
|
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +0,0 @@
|
||||||
'@flecks/core:../src': {}
|
|
||||||
'@flecks/core/one:./one': {}
|
|
||||||
'@flecks/core/one/server:./one/server': {}
|
|
||||||
'@flecks/core/two:./two': {}
|
|
|
@ -2,8 +2,8 @@ import {expect} from 'chai';
|
||||||
|
|
||||||
import {Flecks, ById, ByType} from '@flecks/core';
|
import {Flecks, ById, ByType} from '@flecks/core';
|
||||||
|
|
||||||
const testOne = require('./one');
|
const testOne = require('./packages/one');
|
||||||
const testTwo = require('./two');
|
const testTwo = require('./packages/two');
|
||||||
|
|
||||||
it('can gather', () => {
|
it('can gather', () => {
|
||||||
const flecks = Flecks.from({
|
const flecks = Flecks.from({
|
||||||
|
|
|
@ -2,7 +2,7 @@ import {expect} from 'chai';
|
||||||
|
|
||||||
import {Flecks} from '@flecks/core';
|
import {Flecks} from '@flecks/core';
|
||||||
|
|
||||||
const testOne = require('./one');
|
const testOne = require('./packages/one');
|
||||||
|
|
||||||
it('can create an empty instance', () => {
|
it('can create an empty instance', () => {
|
||||||
const flecks = new Flecks();
|
const flecks = new Flecks();
|
||||||
|
|
|
@ -7,8 +7,8 @@ chai.use(chaiAsPromised);
|
||||||
|
|
||||||
const {expect} = chai;
|
const {expect} = chai;
|
||||||
|
|
||||||
const testOne = require('./one');
|
const testOne = require('./packages/one');
|
||||||
const testTwo = require('./two');
|
const testTwo = require('./packages/two');
|
||||||
|
|
||||||
let flecks;
|
let flecks;
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,9 @@ import {expect} from 'chai';
|
||||||
|
|
||||||
import {Flecks} from '@flecks/core';
|
import {Flecks} from '@flecks/core';
|
||||||
|
|
||||||
const testOne = require('./one');
|
const testOne = require('./packages/one');
|
||||||
const testTwo = require('./two');
|
const testTwo = require('./packages/two');
|
||||||
const testThree = require('./three');
|
const testThree = require('./packages/three');
|
||||||
|
|
||||||
it('can make middleware', (done) => {
|
it('can make middleware', (done) => {
|
||||||
const flecks = Flecks.from({
|
const flecks = Flecks.from({
|
||||||
|
|
51
packages/core/test/platforms/server/bootstrap.js
vendored
51
packages/core/test/platforms/server/bootstrap.js
vendored
|
@ -1,51 +0,0 @@
|
||||||
import {expect} from 'chai';
|
|
||||||
|
|
||||||
// eslint-disable-next-line import/no-unresolved, import/no-extraneous-dependencies
|
|
||||||
import {Flecks} from '../../../src/server';
|
|
||||||
|
|
||||||
it('bootstraps FLECKS_CORE_ROOT by default', () => {
|
|
||||||
const flecks = Flecks.bootstrap();
|
|
||||||
expect(flecks.fleck('@flecks/core')).to.not.equal(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('bootstraps server platform by default', () => {
|
|
||||||
const flecks = Flecks.bootstrap();
|
|
||||||
expect(flecks.fleck('@flecks/core/server')).to.not.equal(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can bootstrap from a foreign root', () => {
|
|
||||||
const flecks = Flecks.bootstrap({
|
|
||||||
root: './test',
|
|
||||||
});
|
|
||||||
expect(flecks.fleck('@flecks/core/one')).to.not.equal(undefined);
|
|
||||||
expect(flecks.fleck('@flecks/core/two')).to.not.equal(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can bootstrap other platforms', () => {
|
|
||||||
const flecks = Flecks.bootstrap({
|
|
||||||
platforms: ['client'],
|
|
||||||
root: './test',
|
|
||||||
});
|
|
||||||
expect(flecks.fleck('@flecks/core/one')).to.not.equal(undefined);
|
|
||||||
expect(flecks.fleck('@flecks/core/one/client')).to.not.equal(undefined);
|
|
||||||
expect(flecks.fleck('@flecks/core/one/server')).to.not.equal(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('can exclude platforms', () => {
|
|
||||||
const flecks = Flecks.bootstrap({
|
|
||||||
platforms: ['client', '!server'],
|
|
||||||
root: './test',
|
|
||||||
});
|
|
||||||
expect(flecks.fleck('@flecks/core/one')).to.not.equal(undefined);
|
|
||||||
expect(flecks.fleck('@flecks/core/one/client')).to.not.equal(undefined);
|
|
||||||
expect(flecks.fleck('@flecks/core/one/server')).to.equal(undefined);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('provides webpack goodies in nodespace', () => {
|
|
||||||
const flecks = Flecks.bootstrap({
|
|
||||||
root: './test',
|
|
||||||
});
|
|
||||||
flecks.fleck('@flecks/core/one').testNodespace().forEach((result) => {
|
|
||||||
expect(result).to.not.equal('undefined');
|
|
||||||
});
|
|
||||||
});
|
|
80
packages/core/test/server/explicate.js
Normal file
80
packages/core/test/server/explicate.js
Normal file
|
@ -0,0 +1,80 @@
|
||||||
|
import {join} from 'path';
|
||||||
|
|
||||||
|
import {expect} from 'chai';
|
||||||
|
|
||||||
|
import explicate from '@flecks/core/build/explicate';
|
||||||
|
import Resolver from '@flecks/core/build/resolver';
|
||||||
|
|
||||||
|
const {
|
||||||
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
|
const root = join(FLECKS_CORE_ROOT, 'test', 'server', 'explicate');
|
||||||
|
|
||||||
|
function createExplication(paths, platforms) {
|
||||||
|
const resolver = new Resolver({modules: [join(root, 'fake_node_modules')]});
|
||||||
|
return explicate(
|
||||||
|
paths,
|
||||||
|
{
|
||||||
|
platforms,
|
||||||
|
resolver,
|
||||||
|
root,
|
||||||
|
importer: (request) => __non_webpack_require__(request),
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('explication', () => {
|
||||||
|
|
||||||
|
it('derives platforms', async () => {
|
||||||
|
expect(Object.keys((await createExplication(['platformed'])).descriptors))
|
||||||
|
.to.deep.equal([
|
||||||
|
'platformed', 'platformed/server',
|
||||||
|
]);
|
||||||
|
expect(Object.keys((await createExplication(['server-only'])).descriptors))
|
||||||
|
.to.deep.equal([
|
||||||
|
'server-only/server',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('derives through bootstrap', async () => {
|
||||||
|
expect(Object.keys((await createExplication(['real-root'])).descriptors))
|
||||||
|
.to.deep.equal([
|
||||||
|
'dependency', 'dependency/server',
|
||||||
|
'real-root', 'real-root/server',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('excludes platforms', async () => {
|
||||||
|
expect(Object.keys(
|
||||||
|
(await createExplication(
|
||||||
|
['platformed/client', 'dependency'],
|
||||||
|
['server', '!client'],
|
||||||
|
)).descriptors,
|
||||||
|
))
|
||||||
|
.to.deep.equal([
|
||||||
|
'dependency', 'dependency/server',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('explicates parents first', async () => {
|
||||||
|
expect(Object.keys((await createExplication(['real-root/server'])).descriptors))
|
||||||
|
.to.deep.equal([
|
||||||
|
'dependency', 'dependency/server',
|
||||||
|
'real-root', 'real-root/server',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('explicates only bootstrapped', async () => {
|
||||||
|
expect(Object.keys((await createExplication(['only-bootstrapped'])).descriptors))
|
||||||
|
.to.deep.equal([
|
||||||
|
'only-bootstrapped',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('skips nonexistent', async () => {
|
||||||
|
expect(await createExplication(['real-root/nonexistent']))
|
||||||
|
.to.deep.equal({descriptors: {}, roots: {}});
|
||||||
|
});
|
||||||
|
|
||||||
|
});
|
0
packages/core/test/server/explicate/fake_node_modules/dependency/index.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/dependency/index.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/dependency/server/index.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/dependency/server/index.js
generated
Normal file
1
packages/core/test/server/explicate/fake_node_modules/only-bootstrapped/package.json
generated
Normal file
1
packages/core/test/server/explicate/fake_node_modules/only-bootstrapped/package.json
generated
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
0
packages/core/test/server/explicate/fake_node_modules/platformed/client/index.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/platformed/client/index.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/platformed/index.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/platformed/index.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/platformed/server/index.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/platformed/server/index.js
generated
Normal file
1
packages/core/test/server/explicate/fake_node_modules/real-root/build/flecks.bootstrap.js
generated
Normal file
1
packages/core/test/server/explicate/fake_node_modules/real-root/build/flecks.bootstrap.js
generated
Normal file
|
@ -0,0 +1 @@
|
||||||
|
exports.dependencies = ['dependency'];
|
0
packages/core/test/server/explicate/fake_node_modules/real-root/index.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/real-root/index.js
generated
Normal file
1
packages/core/test/server/explicate/fake_node_modules/real-root/package.json
generated
Normal file
1
packages/core/test/server/explicate/fake_node_modules/real-root/package.json
generated
Normal file
|
@ -0,0 +1 @@
|
||||||
|
{}
|
0
packages/core/test/server/explicate/fake_node_modules/real-root/server/index.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/real-root/server/index.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/server-only/server.js
generated
Normal file
0
packages/core/test/server/explicate/fake_node_modules/server-only/server.js
generated
Normal file
24
packages/core/test/server/resolve.js
Normal file
24
packages/core/test/server/resolve.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import {join} from 'path';
|
||||||
|
|
||||||
|
import {expect} from 'chai';
|
||||||
|
|
||||||
|
import Resolver from '@flecks/core/build/resolver';
|
||||||
|
|
||||||
|
const {
|
||||||
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
|
} = process.env;
|
||||||
|
|
||||||
|
it('can resolve', async () => {
|
||||||
|
const resolver = new Resolver();
|
||||||
|
expect(await resolver.resolve('./test/server/resolve'))
|
||||||
|
.to.equal(join(FLECKS_CORE_ROOT, 'test', 'server', 'resolve.js'));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can create aliases at runtime', async () => {
|
||||||
|
const resolver = new Resolver();
|
||||||
|
expect(await resolver.resolve('./test/server/foobar'))
|
||||||
|
.to.be.undefined;
|
||||||
|
resolver.addAlias('./test/server/foobar', './test/server/resolve');
|
||||||
|
expect(await resolver.resolve('./test/server/foobar'))
|
||||||
|
.to.not.be.undefined;
|
||||||
|
});
|
|
@ -1,3 +1,5 @@
|
||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
import {join} from 'path';
|
import {join} from 'path';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
|
@ -19,7 +21,7 @@ const {
|
||||||
(async () => {
|
(async () => {
|
||||||
program.argument('<app>', 'name of the app to create');
|
program.argument('<app>', 'name of the app to create');
|
||||||
program.addOption(
|
program.addOption(
|
||||||
new Option('--package-manager <binary>', 'package manager binary')
|
new Option('-pm,--package-manager <binary>', 'package manager binary')
|
||||||
.choices(['npm', 'bun', 'yarn'])
|
.choices(['npm', 'bun', 'yarn'])
|
||||||
.default('npm'),
|
.default('npm'),
|
||||||
);
|
);
|
|
@ -1,6 +1,6 @@
|
||||||
const {copy, executable} = require('@flecks/core/server');
|
const {copy, executable} = require('@flecks/core/server');
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
const configFn = require('@flecks/fleck/server/build/fleck.webpack.config');
|
const configFn = require('@flecks/fleck/build/fleck.webpack.config');
|
||||||
|
|
||||||
module.exports = async (env, argv, flecks) => {
|
module.exports = async (env, argv, flecks) => {
|
||||||
const config = await configFn(env, argv, flecks);
|
const config = await configFn(env, argv, flecks);
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
import {
|
import {stat} from 'fs/promises';
|
||||||
stat,
|
|
||||||
} from 'fs/promises';
|
|
||||||
import {basename, dirname, join} from 'path';
|
import {basename, dirname, join} from 'path';
|
||||||
|
|
||||||
import {
|
import {JsonStream, transform} from '@flecks/core/server';
|
||||||
JsonStream,
|
|
||||||
transform,
|
|
||||||
} from '@flecks/core/server';
|
|
||||||
|
|
||||||
import FileTree from './tree';
|
import FileTree from './tree';
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"version": "2.0.3",
|
"version": "3.0.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"create-app": "./cli.js"
|
"create-app": "./cli.js"
|
||||||
},
|
},
|
||||||
|
@ -22,15 +22,14 @@
|
||||||
"files": [
|
"files": [
|
||||||
"cli.js",
|
"cli.js",
|
||||||
"server.js",
|
"server.js",
|
||||||
"src",
|
|
||||||
"template"
|
"template"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@flecks/core": "^2.0.3",
|
"@flecks/core": "^3.0.0",
|
||||||
"minimatch": "^5.0.1",
|
"minimatch": "^5.0.1",
|
||||||
"validate-npm-package-name": "^3.0.0"
|
"validate-npm-package-name": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@flecks/fleck": "^2.0.3"
|
"@flecks/fleck": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1 @@
|
||||||
export {default as validate} from 'validate-npm-package-name';
|
export {default as validate} from 'validate-npm-package-name';
|
||||||
|
|
||||||
export {default as build} from './build';
|
|
||||||
export {default as move, testDestination} from './move';
|
|
||||||
export {default as FileTree} from './tree';
|
|
||||||
|
|
|
@ -9,11 +9,11 @@
|
||||||
"start": "DEBUG=@flecks/*,-*:silly npm run dev"
|
"start": "DEBUG=@flecks/*,-*:silly npm run dev"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@flecks/core": "^2.0.0",
|
"@flecks/core": "3.0.0",
|
||||||
"@flecks/server": "^2.0.0"
|
"@flecks/server": "3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@flecks/create-fleck": "^2.0.0",
|
"@flecks/create-fleck": "3.0.0",
|
||||||
"lerna": "^3.22.1"
|
"lerna": "^3.22.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
import {stat} from 'fs/promises';
|
#!/usr/bin/env node
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {
|
const {stat} = require('fs/promises');
|
||||||
build,
|
const {join} = require('path');
|
||||||
move,
|
|
||||||
testDestination,
|
const addFleckToYml = require('@flecks/core/build/add-fleck-to-yml');
|
||||||
validate,
|
const {Server, program} = require('@flecks/core/server');
|
||||||
} from '@flecks/create-app/server';
|
const build = require('@flecks/create-app/build/build');
|
||||||
import {Flecks, program} from '@flecks/core/server';
|
const move = require('@flecks/create-app/build/move');
|
||||||
|
const testDestination = require('@flecks/create-app/build/testDestination');
|
||||||
|
const {validate} = require('@flecks/create-app/server');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
|
@ -65,8 +66,8 @@ const target = async (fleck) => {
|
||||||
program.action(async (fleck, o) => {
|
program.action(async (fleck, o) => {
|
||||||
const {alias, add} = o;
|
const {alias, add} = o;
|
||||||
try {
|
try {
|
||||||
const flecks = await Flecks.bootstrap();
|
const flecks = await Server.from();
|
||||||
const {packageManager} = flecks.get('@flecks/core/server');
|
const {packageManager} = flecks.get('@flecks/core');
|
||||||
const isMonorepo = await checkIsMonorepo();
|
const isMonorepo = await checkIsMonorepo();
|
||||||
const [scope, pkg] = await target(fleck);
|
const [scope, pkg] = await target(fleck);
|
||||||
const name = [scope, pkg].filter((e) => !!e).join('/');
|
const name = [scope, pkg].filter((e) => !!e).join('/');
|
||||||
|
@ -86,7 +87,7 @@ const target = async (fleck) => {
|
||||||
await fileTree.writeTo(destination);
|
await fileTree.writeTo(destination);
|
||||||
await build(packageManager, destination);
|
await build(packageManager, destination);
|
||||||
if (isMonorepo && add) {
|
if (isMonorepo && add) {
|
||||||
await Flecks.addFleckToYml(...[name].concat(alias ? pkg : []));
|
await addFleckToYml(...[name].concat(alias ? pkg : []));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
|
@ -1,6 +1,6 @@
|
||||||
const {copy, executable} = require('@flecks/core/server');
|
const {copy, executable} = require('@flecks/core/server');
|
||||||
// eslint-disable-next-line import/no-extraneous-dependencies
|
// eslint-disable-next-line import/no-extraneous-dependencies
|
||||||
const configFn = require('@flecks/fleck/server/build/fleck.webpack.config');
|
const configFn = require('@flecks/fleck/build/fleck.webpack.config');
|
||||||
|
|
||||||
module.exports = async (env, argv, flecks) => {
|
module.exports = async (env, argv, flecks) => {
|
||||||
const config = await configFn(env, argv, flecks);
|
const config = await configFn(env, argv, flecks);
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"version": "2.0.3",
|
"version": "3.0.0",
|
||||||
"bin": {
|
"bin": {
|
||||||
"create-fleck": "./cli.js"
|
"create-fleck": "./cli.js"
|
||||||
},
|
},
|
||||||
|
@ -20,15 +20,13 @@
|
||||||
"test": "flecks test"
|
"test": "flecks test"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"cli.js",
|
|
||||||
"src",
|
|
||||||
"template"
|
"template"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@flecks/core": "^2.0.3",
|
"@flecks/core": "^3.0.0",
|
||||||
"@flecks/create-app": "^2.0.3"
|
"@flecks/create-app": "^3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@flecks/fleck": "^2.0.3"
|
"@flecks/fleck": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,9 +11,9 @@
|
||||||
"index.js"
|
"index.js"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@flecks/core": "^2.0.0"
|
"@flecks/core": "3.0.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@flecks/fleck": "^2.0.0"
|
"@flecks/fleck": "3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"version": "2.0.3",
|
"version": "3.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "flecks build",
|
"build": "flecks build",
|
||||||
"clean": "flecks clean",
|
"clean": "flecks clean",
|
||||||
|
@ -20,11 +20,11 @@
|
||||||
"server.js"
|
"server.js"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@flecks/core": "^2.0.3",
|
"@flecks/core": "^3.0.0",
|
||||||
"sequelize": "^6.3.5",
|
"sequelize": "^6.3.5",
|
||||||
"sqlite3": "^5.0.2"
|
"sqlite3": "^5.0.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@flecks/fleck": "^2.0.3"
|
"@flecks/fleck": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"version": "2.0.3",
|
"version": "3.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "flecks build",
|
"build": "flecks build",
|
||||||
|
@ -21,10 +21,10 @@
|
||||||
"server.js"
|
"server.js"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@flecks/core": "^2.0.3",
|
"@flecks/core": "^3.0.0",
|
||||||
"debug": "^4.3.3"
|
"debug": "^4.3.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@flecks/fleck": "^2.0.3"
|
"@flecks/fleck": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,24 +1,25 @@
|
||||||
import {
|
const {
|
||||||
access,
|
access,
|
||||||
cp,
|
cp,
|
||||||
mkdir,
|
mkdir,
|
||||||
rename,
|
rename,
|
||||||
rmdir,
|
rmdir,
|
||||||
} from 'fs/promises';
|
} = require('fs/promises');
|
||||||
import {dirname, join} from 'path';
|
const {dirname, join} = require('path');
|
||||||
|
|
||||||
import {
|
const {Argument} = require('@flecks/core/build/commands');
|
||||||
|
|
||||||
|
const {
|
||||||
generate,
|
generate,
|
||||||
resolveSiteDir,
|
resolveSiteDir,
|
||||||
spawn,
|
spawn,
|
||||||
} from './docusaurus';
|
} = require('./docusaurus');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
} = process.env;
|
} = process.env;
|
||||||
|
|
||||||
export default (program, flecks) => {
|
module.exports = (program, flecks) => {
|
||||||
const {Argument} = flecks.fleck('@flecks/core/server');
|
|
||||||
const commands = {};
|
const commands = {};
|
||||||
const siteDirArgument = new Argument('[siteDir]', 'Docusaurus directory');
|
const siteDirArgument = new Argument('[siteDir]', 'Docusaurus directory');
|
||||||
siteDirArgument.defaultValue = 'website';
|
siteDirArgument.defaultValue = 'website';
|
|
@ -1,23 +1,23 @@
|
||||||
import {mkdir, writeFile} from 'fs/promises';
|
const {mkdir, writeFile} = require('fs/promises');
|
||||||
import {isAbsolute, join, resolve} from 'path';
|
const {isAbsolute, join, resolve} = require('path');
|
||||||
|
|
||||||
import {spawnWith} from '@flecks/core/server';
|
const {spawnWith} = require('@flecks/core/server');
|
||||||
import {themes as prismThemes} from 'prism-react-renderer';
|
const {themes: prismThemes} = require('prism-react-renderer');
|
||||||
import {rimraf} from 'rimraf';
|
const {rimraf} = require('rimraf');
|
||||||
|
|
||||||
import {
|
const {
|
||||||
generateBuildConfigsPage,
|
generateBuildConfigsPage,
|
||||||
generateConfigPage,
|
generateConfigPage,
|
||||||
generateHookPage,
|
generateHookPage,
|
||||||
generateTodoPage,
|
generateTodoPage,
|
||||||
} from './generate';
|
} = require('./generate');
|
||||||
import {parseFlecks} from './parser';
|
const {parseFlecks} = require('./parser');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
} = process.env;
|
} = process.env;
|
||||||
|
|
||||||
export function configDefaults() {
|
exports.configDefaults = function configDefaults() {
|
||||||
/** @type {import('@docusaurus/types').Config} */
|
/** @type {import('@docusaurus/types').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
tagline: 'built with flecks',
|
tagline: 'built with flecks',
|
||||||
|
@ -49,15 +49,15 @@ export function configDefaults() {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
return config;
|
return config;
|
||||||
}
|
};
|
||||||
|
|
||||||
export function resolveSiteDir(siteDir) {
|
exports.resolveSiteDir = function resolveSiteDir(siteDir) {
|
||||||
return isAbsolute(siteDir)
|
return isAbsolute(siteDir)
|
||||||
? siteDir
|
? siteDir
|
||||||
: resolve(FLECKS_CORE_ROOT, siteDir);
|
: resolve(FLECKS_CORE_ROOT, siteDir);
|
||||||
}
|
};
|
||||||
|
|
||||||
export async function generate(flecks, siteDir) {
|
exports.generate = async function generate(flecks, siteDir) {
|
||||||
// Generate "docs".
|
// Generate "docs".
|
||||||
const docsDirectory = join(siteDir, 'docs', 'flecks');
|
const docsDirectory = join(siteDir, 'docs', 'flecks');
|
||||||
await rimraf(docsDirectory);
|
await rimraf(docsDirectory);
|
||||||
|
@ -72,9 +72,9 @@ export async function generate(flecks, siteDir) {
|
||||||
await writeFile(join(generatedDirectory, 'TODO.md'), todoPage);
|
await writeFile(join(generatedDirectory, 'TODO.md'), todoPage);
|
||||||
await writeFile(join(generatedDirectory, 'build-configs.md'), buildConfigsPage);
|
await writeFile(join(generatedDirectory, 'build-configs.md'), buildConfigsPage);
|
||||||
await writeFile(join(generatedDirectory, 'config.mdx'), configPage);
|
await writeFile(join(generatedDirectory, 'config.mdx'), configPage);
|
||||||
}
|
};
|
||||||
|
|
||||||
export function spawn(subcommand, siteDir) {
|
exports.spawn = function spawn(subcommand, siteDir) {
|
||||||
const args = [];
|
const args = [];
|
||||||
switch (subcommand) {
|
switch (subcommand) {
|
||||||
case 'start':
|
case 'start':
|
||||||
|
@ -112,4 +112,4 @@ export function spawn(subcommand, siteDir) {
|
||||||
child.kill();
|
child.kill();
|
||||||
});
|
});
|
||||||
return child;
|
return child;
|
||||||
}
|
};
|
|
@ -1,8 +1,6 @@
|
||||||
import commands from './commands';
|
const commands = require('./commands');
|
||||||
|
|
||||||
export {configDefaults} from './docusaurus';
|
exports.hooks = {
|
||||||
|
|
||||||
export const hooks = {
|
|
||||||
'@flecks/core.commands': commands,
|
'@flecks/core.commands': commands,
|
||||||
'@flecks/core.config': () => ({
|
'@flecks/core.config': () => ({
|
||||||
/**
|
/**
|
|
@ -1,2 +0,0 @@
|
||||||
'@flecks/core': {}
|
|
||||||
'@flecks/fleck': {}
|
|
|
@ -6,7 +6,7 @@ const makeFilenameRewriter = (filenameRewriters) => (filename, line, column) =>
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const generateBuildConfigsPage = (buildConfigs) => {
|
exports.generateBuildConfigsPage = (buildConfigs) => {
|
||||||
const source = [];
|
const source = [];
|
||||||
source.push('# Build configuration');
|
source.push('# Build configuration');
|
||||||
source.push('');
|
source.push('');
|
||||||
|
@ -25,9 +25,9 @@ export const generateBuildConfigsPage = (buildConfigs) => {
|
||||||
return source.join('\n');
|
return source.join('\n');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generateConfigPage = (configs) => {
|
exports.generateConfigPage = (configs) => {
|
||||||
const source = [];
|
const source = [];
|
||||||
source.push("import CodeBlock from '@theme/CodeBlock';");
|
source.push("const CodeBlock = require('@theme/CodeBlock');");
|
||||||
source.push('');
|
source.push('');
|
||||||
source.push('# Fleck configuration');
|
source.push('# Fleck configuration');
|
||||||
source.push('');
|
source.push('');
|
||||||
|
@ -61,8 +61,8 @@ export const generateConfigPage = (configs) => {
|
||||||
return source.join('\n');
|
return source.join('\n');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generateHookPage = (hooks, flecks) => {
|
exports.generateHookPage = (hooks, flecks) => {
|
||||||
const {filenameRewriters} = flecks.get('@flecks/dox/server');
|
const {filenameRewriters} = flecks.get('@flecks/dox');
|
||||||
const rewriteFilename = makeFilenameRewriter(filenameRewriters);
|
const rewriteFilename = makeFilenameRewriter(filenameRewriters);
|
||||||
const source = [];
|
const source = [];
|
||||||
source.push('# Hooks');
|
source.push('# Hooks');
|
||||||
|
@ -126,8 +126,8 @@ export const generateHookPage = (hooks, flecks) => {
|
||||||
return source.join('\n');
|
return source.join('\n');
|
||||||
};
|
};
|
||||||
|
|
||||||
export const generateTodoPage = (todos, flecks) => {
|
exports.generateTodoPage = (todos, flecks) => {
|
||||||
const {filenameRewriters} = flecks.get('@flecks/dox/server');
|
const {filenameRewriters} = flecks.get('@flecks/dox');
|
||||||
const rewriteFilename = makeFilenameRewriter(filenameRewriters);
|
const rewriteFilename = makeFilenameRewriter(filenameRewriters);
|
||||||
const source = [];
|
const source = [];
|
||||||
source.push('# TODO list');
|
source.push('# TODO list');
|
|
@ -1,14 +1,14 @@
|
||||||
import {readFile} from 'fs/promises';
|
const {readFile} = require('fs/promises');
|
||||||
import {
|
const {
|
||||||
basename,
|
basename,
|
||||||
dirname,
|
dirname,
|
||||||
extname,
|
extname,
|
||||||
join,
|
join,
|
||||||
} from 'path';
|
} = require('path');
|
||||||
|
|
||||||
import {transformAsync} from '@babel/core';
|
const {transformAsync} = require('@babel/core');
|
||||||
import traverse from '@babel/traverse';
|
const traverse = require('@babel/traverse');
|
||||||
import {
|
const {
|
||||||
isArrayExpression,
|
isArrayExpression,
|
||||||
isArrowFunctionExpression,
|
isArrowFunctionExpression,
|
||||||
isIdentifier,
|
isIdentifier,
|
||||||
|
@ -18,9 +18,9 @@ import {
|
||||||
isStringLiteral,
|
isStringLiteral,
|
||||||
isThisExpression,
|
isThisExpression,
|
||||||
isVariableDeclaration,
|
isVariableDeclaration,
|
||||||
} from '@babel/types';
|
} = require('@babel/types');
|
||||||
import {glob, require as R} from '@flecks/core/server';
|
const {glob} = require('@flecks/core/server');
|
||||||
import {parse as parseComment} from 'comment-parser';
|
const {parse: parseComment} = require('comment-parser');
|
||||||
|
|
||||||
class ParserState {
|
class ParserState {
|
||||||
|
|
||||||
|
@ -272,7 +272,7 @@ const FlecksTodos = (state, filename) => ({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const parseCode = async (code) => {
|
exports.parseCode = async (code) => {
|
||||||
const config = {
|
const config = {
|
||||||
ast: true,
|
ast: true,
|
||||||
code: false,
|
code: false,
|
||||||
|
@ -281,10 +281,10 @@ export const parseCode = async (code) => {
|
||||||
return ast;
|
return ast;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const parseFile = async (filename, resolved, state) => {
|
exports.parseFile = async (filename, resolved, state) => {
|
||||||
const buffer = await readFile(filename);
|
const buffer = await readFile(filename);
|
||||||
const source = buffer.toString('utf8');
|
const source = buffer.toString('utf8');
|
||||||
const ast = await parseCode(source);
|
const ast = await exports.parseCode(source);
|
||||||
traverse(ast, FlecksBuildConfigs(state, resolved));
|
traverse(ast, FlecksBuildConfigs(state, resolved));
|
||||||
traverse(ast, FlecksConfigs(state, resolved, source));
|
traverse(ast, FlecksConfigs(state, resolved, source));
|
||||||
traverse(ast, FlecksInvocations(state, resolved));
|
traverse(ast, FlecksInvocations(state, resolved));
|
||||||
|
@ -294,19 +294,19 @@ export const parseFile = async (filename, resolved, state) => {
|
||||||
|
|
||||||
const fleckSources = async (path) => glob(join(path, 'src', '**', '*.js'));
|
const fleckSources = async (path) => glob(join(path, 'src', '**', '*.js'));
|
||||||
|
|
||||||
export const parseFleckRoot = async (root, state) => {
|
exports.parseFleckRoot = async (root, state) => {
|
||||||
const resolved = dirname(R.resolve(join(root, 'package.json')));
|
const resolved = dirname(require.resolve(join(root, 'package.json')));
|
||||||
const sources = await fleckSources(resolved);
|
const sources = await fleckSources(resolved);
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
sources.map(async (source) => {
|
sources.map(async (source) => {
|
||||||
// @todo Aliased fleck paths are gonna be bad.
|
// @todo Aliased fleck paths are gonna be bad.
|
||||||
await parseFile(source, join(root, source.slice(resolved.length)), state);
|
await exports.parseFile(source, join(root, source.slice(resolved.length)), state);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
try {
|
try {
|
||||||
const buffer = await readFile(join(resolved, 'build', 'dox', 'hooks.js'));
|
const buffer = await readFile(join(resolved, 'build', 'dox', 'hooks.js'));
|
||||||
const source = buffer.toString('utf8');
|
const source = buffer.toString('utf8');
|
||||||
const ast = await parseCode(source);
|
const ast = await exports.parseCode(source);
|
||||||
traverse(ast, FlecksSpecifications(state, source));
|
traverse(ast, FlecksSpecifications(state, source));
|
||||||
}
|
}
|
||||||
catch (error) {
|
catch (error) {
|
||||||
|
@ -316,7 +316,7 @@ export const parseFleckRoot = async (root, state) => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const parseFlecks = async (flecks) => {
|
exports.parseFlecks = async (flecks) => {
|
||||||
const state = new ParserState();
|
const state = new ParserState();
|
||||||
const paths = Object.keys(flecks.resolver);
|
const paths = Object.keys(flecks.resolver);
|
||||||
const roots = Array.from(new Set(
|
const roots = Array.from(new Set(
|
||||||
|
@ -327,7 +327,7 @@ export const parseFlecks = async (flecks) => {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
roots
|
roots
|
||||||
.map(async (root) => {
|
.map(async (root) => {
|
||||||
await parseFleckRoot(root, state);
|
await exports.parseFleckRoot(root, state);
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
return state;
|
return state;
|
|
@ -8,7 +8,7 @@
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"version": "2.0.3",
|
"version": "3.0.0",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "flecks build",
|
"build": "flecks build",
|
||||||
|
@ -18,7 +18,6 @@
|
||||||
"test": "flecks test"
|
"test": "flecks test"
|
||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"server.js",
|
|
||||||
"website"
|
"website"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -29,7 +28,7 @@
|
||||||
"@docusaurus/module-type-aliases": "3.0.1",
|
"@docusaurus/module-type-aliases": "3.0.1",
|
||||||
"@docusaurus/preset-classic": "3.0.1",
|
"@docusaurus/preset-classic": "3.0.1",
|
||||||
"@docusaurus/types": "3.0.1",
|
"@docusaurus/types": "3.0.1",
|
||||||
"@flecks/core": "^2.0.3",
|
"@flecks/core": "^3.0.0",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"comment-parser": "^1.3.0",
|
"comment-parser": "^1.3.0",
|
||||||
|
@ -40,6 +39,6 @@
|
||||||
"rimraf": "^5.0.5"
|
"rimraf": "^5.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@flecks/fleck": "^2.0.3"
|
"@flecks/fleck": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,10 +4,9 @@
|
||||||
// There are various equivalent ways to declare your Docusaurus config.
|
// There are various equivalent ways to declare your Docusaurus config.
|
||||||
// See: https://docusaurus.io/docs/api/docusaurus-config
|
// See: https://docusaurus.io/docs/api/docusaurus-config
|
||||||
|
|
||||||
// For some reason we get a webpack warning if we use import here...
|
const {configDefaults} = require('@flecks/dox/build/docusaurus');
|
||||||
const {configDefaults} = require('@flecks/dox/server'); // eslint-disable-line import/no-extraneous-dependencies
|
|
||||||
|
|
||||||
export default async function flecksDocusaurus() {
|
module.exports = async function flecksDocusaurus() {
|
||||||
const defaults = configDefaults();
|
const defaults = configDefaults();
|
||||||
/** @type {import('@docusaurus/types').Config} */
|
/** @type {import('@docusaurus/types').Config} */
|
||||||
const config = {
|
const config = {
|
||||||
|
@ -18,4 +17,4 @@ export default async function flecksDocusaurus() {
|
||||||
baseUrl: '/',
|
baseUrl: '/',
|
||||||
};
|
};
|
||||||
return config;
|
return config;
|
||||||
}
|
};
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import clsx from 'clsx';
|
const clsx = require('clsx');
|
||||||
import Link from '@docusaurus/Link';
|
const Link = require('@docusaurus/Link');
|
||||||
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
|
const useDocusaurusContext = require('@docusaurus/useDocusaurusContext');
|
||||||
import Layout from '@theme/Layout';
|
const Layout = require('@theme/Layout');
|
||||||
|
|
||||||
import Heading from '@theme/Heading';
|
const Heading = require('@theme/Heading');
|
||||||
import styles from './index.module.css';
|
import styles from './index.module.css';
|
||||||
|
|
||||||
function HomepageHeader() {
|
function HomepageHeader() {
|
||||||
|
|
59
packages/electron/build/flecks.bootstrap.js
Normal file
59
packages/electron/build/flecks.bootstrap.js
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
const {join} = require('path');
|
||||||
|
|
||||||
|
const {banner} = require('@flecks/core/server');
|
||||||
|
|
||||||
|
exports.hooks = {
|
||||||
|
'@flecks/core.build': (target, config) => {
|
||||||
|
if ('server' === target) {
|
||||||
|
config.plugins.push(
|
||||||
|
banner({
|
||||||
|
// Bootstrap our `require()` magic.
|
||||||
|
banner: "require('module').Module._initPaths();",
|
||||||
|
include: 'index.js',
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'@flecks/core.config': () => ({
|
||||||
|
/**
|
||||||
|
* Browser window options.
|
||||||
|
*
|
||||||
|
* See: https://www.electronjs.org/docs/latest/api/browser-window
|
||||||
|
*/
|
||||||
|
browserWindowOptions: {},
|
||||||
|
/**
|
||||||
|
* Install devtools extensions (by default).
|
||||||
|
*
|
||||||
|
* If `true`, will install some devtools extensions based on which flecks are enabled.
|
||||||
|
*
|
||||||
|
* You can pass an array of Chrome store IDs to install a list of custom extensions.
|
||||||
|
*
|
||||||
|
* Extensions will not be installed if `'production' === process.env.NODE_ENV`
|
||||||
|
*/
|
||||||
|
installExtensions: true,
|
||||||
|
/**
|
||||||
|
* Quit the app when all windows are closed.
|
||||||
|
*/
|
||||||
|
quitOnClosed: true,
|
||||||
|
/**
|
||||||
|
* The URL to load in electron by default.
|
||||||
|
*
|
||||||
|
* Defaults to `http://${flecks.get('@flecks/web.public')}`.
|
||||||
|
*/
|
||||||
|
url: undefined,
|
||||||
|
}),
|
||||||
|
'@flecks/core.build.alter': (configs) => {
|
||||||
|
const {server: config} = configs;
|
||||||
|
if (config) {
|
||||||
|
const plugin = config.plugins.find(({pluginName}) => pluginName === 'StartServerPlugin');
|
||||||
|
// Extremely hackish, c'est la vie.
|
||||||
|
if (plugin) {
|
||||||
|
const {exec} = plugin.options;
|
||||||
|
plugin.options.exec = (compilation) => {
|
||||||
|
plugin.options.args = [join(config.output.path, compilation.getPath(exec))];
|
||||||
|
return join('..', '..', 'node_modules', '.bin', 'electron');
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
|
@ -8,7 +8,7 @@
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
},
|
},
|
||||||
"version": "2.0.3",
|
"version": "3.0.0",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "flecks build",
|
"build": "flecks build",
|
||||||
"clean": "flecks clean",
|
"clean": "flecks clean",
|
||||||
|
@ -20,11 +20,11 @@
|
||||||
"server.js"
|
"server.js"
|
||||||
],
|
],
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@flecks/core": "^2.0.3",
|
"@flecks/core": "^3.0.0",
|
||||||
"electron": "^18.0.1",
|
"electron": "^18.0.1",
|
||||||
"electron-devtools-installer": "^3.2.0"
|
"electron-devtools-installer": "^3.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@flecks/fleck": "^2.0.3"
|
"@flecks/fleck": "^3.0.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,4 @@
|
||||||
import {join} from 'path';
|
|
||||||
|
|
||||||
import {Flecks} from '@flecks/core';
|
import {Flecks} from '@flecks/core';
|
||||||
import {banner} from '@flecks/core/server';
|
|
||||||
|
|
||||||
const electron = __non_webpack_require__('electron');
|
const electron = __non_webpack_require__('electron');
|
||||||
|
|
||||||
|
@ -13,66 +10,13 @@ let win;
|
||||||
|
|
||||||
async function createWindow(flecks) {
|
async function createWindow(flecks) {
|
||||||
const {BrowserWindow} = flecks.electron;
|
const {BrowserWindow} = flecks.electron;
|
||||||
const {browserWindowOptions} = flecks.get('@flecks/electron/server');
|
const {browserWindowOptions} = flecks.get('@flecks/electron');
|
||||||
flecks.invoke('@flecks/electron/server.browserWindowOptions.alter', browserWindowOptions)
|
flecks.invoke('@flecks/electron/server.browserWindowOptions.alter', browserWindowOptions);
|
||||||
win = new BrowserWindow(browserWindowOptions);
|
win = new BrowserWindow(browserWindowOptions);
|
||||||
await flecks.invokeSequentialAsync('@flecks/electron/server.window', win);
|
await flecks.invokeSequentialAsync('@flecks/electron/server.window', win);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const hooks = {
|
export const hooks = {
|
||||||
'@flecks/core.build': (target, config) => {
|
|
||||||
if ('server' === target) {
|
|
||||||
config.plugins.push(
|
|
||||||
banner({
|
|
||||||
// Bootstrap our `require()` magic.
|
|
||||||
banner: "require('module').Module._initPaths();",
|
|
||||||
include: 'index.js',
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'@flecks/core.config': () => ({
|
|
||||||
/**
|
|
||||||
* Browser window options.
|
|
||||||
*
|
|
||||||
* See: https://www.electronjs.org/docs/latest/api/browser-window
|
|
||||||
*/
|
|
||||||
browserWindowOptions: {},
|
|
||||||
/**
|
|
||||||
* Install devtools extensions (by default).
|
|
||||||
*
|
|
||||||
* If `true`, will install some devtools extensions based on which flecks are enabled.
|
|
||||||
*
|
|
||||||
* You can pass an array of Chrome store IDs to install a list of custom extensions.
|
|
||||||
*
|
|
||||||
* Extensions will not be installed if `'production' === process.env.NODE_ENV`
|
|
||||||
*/
|
|
||||||
installExtensions: true,
|
|
||||||
/**
|
|
||||||
* Quit the app when all windows are closed.
|
|
||||||
*/
|
|
||||||
quitOnClosed: true,
|
|
||||||
/**
|
|
||||||
* The URL to load in electron by default.
|
|
||||||
*
|
|
||||||
* Defaults to `http://${flecks.get('@flecks/web/server.public')}`.
|
|
||||||
*/
|
|
||||||
url: undefined,
|
|
||||||
}),
|
|
||||||
'@flecks/core.build.alter': (configs) => {
|
|
||||||
const {server: config} = configs;
|
|
||||||
if (config) {
|
|
||||||
const plugin = config.plugins.find(({pluginName}) => pluginName === 'StartServerPlugin');
|
|
||||||
// Extremely hackish, c'est la vie.
|
|
||||||
if (plugin) {
|
|
||||||
const {exec} = plugin.options;
|
|
||||||
plugin.options.exec = (compilation) => {
|
|
||||||
plugin.options.args = [join(config.output.path, compilation.getPath(exec))];
|
|
||||||
return join('..', '..', 'node_modules', '.bin', 'electron');
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'@flecks/core.mixin': (Flecks) => (
|
'@flecks/core.mixin': (Flecks) => (
|
||||||
class FlecksWithElectron extends Flecks {
|
class FlecksWithElectron extends Flecks {
|
||||||
|
|
||||||
|
@ -82,7 +26,7 @@ export const hooks = {
|
||||||
),
|
),
|
||||||
'@flecks/electron/server.initialize': async (electron, flecks) => {
|
'@flecks/electron/server.initialize': async (electron, flecks) => {
|
||||||
electron.app.on('window-all-closed', () => {
|
electron.app.on('window-all-closed', () => {
|
||||||
const {quitOnClosed} = flecks.get('@flecks/electron/server');
|
const {quitOnClosed} = flecks.get('@flecks/electron');
|
||||||
if (!quitOnClosed) {
|
if (!quitOnClosed) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -101,11 +45,11 @@ export const hooks = {
|
||||||
await createWindow(flecks);
|
await createWindow(flecks);
|
||||||
},
|
},
|
||||||
'@flecks/electron/server.window': async (win, flecks) => {
|
'@flecks/electron/server.window': async (win, flecks) => {
|
||||||
const {public: $$public} = flecks.get('@flecks/web/server');
|
const {public: $$public} = flecks.get('@flecks/web');
|
||||||
const {
|
const {
|
||||||
installExtensions,
|
installExtensions,
|
||||||
url = `http://${$$public}`,
|
url = `http://${$$public}`,
|
||||||
} = flecks.get('@flecks/electron/server');
|
} = flecks.get('@flecks/electron');
|
||||||
if (installExtensions && 'production' !== NODE_ENV) {
|
if (installExtensions && 'production' !== NODE_ENV) {
|
||||||
const {
|
const {
|
||||||
default: installExtension,
|
default: installExtension,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
import {stat, unlink} from 'fs/promises';
|
const {stat, unlink} = require('fs/promises');
|
||||||
import {join} from 'path';
|
const {join} = require('path');
|
||||||
|
|
||||||
import {D} from '@flecks/core';
|
const {D} = require('@flecks/core');
|
||||||
import {commands as coreCommands, glob} from '@flecks/core/server';
|
const {commands: coreCommands, glob} = require('@flecks/core/server');
|
||||||
import chokidar from 'chokidar';
|
const chokidar = require('chokidar');
|
||||||
import clearModule from 'clear-module';
|
const clearModule = require('clear-module');
|
||||||
import Mocha from 'mocha';
|
const Mocha = require('mocha');
|
||||||
|
|
||||||
const debug = D('@flecks/core.commands');
|
const debug = D('@flecks/core.commands');
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ const {
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
} = process.env;
|
} = process.env;
|
||||||
|
|
||||||
export default (program, flecks) => {
|
module.exports = (program, flecks) => {
|
||||||
const commands = {};
|
const commands = {};
|
||||||
commands.test = {
|
commands.test = {
|
||||||
options: [
|
options: [
|
||||||
|
@ -27,7 +27,7 @@ export default (program, flecks) => {
|
||||||
watch,
|
watch,
|
||||||
} = opts;
|
} = opts;
|
||||||
const {build} = coreCommands(program, flecks);
|
const {build} = coreCommands(program, flecks);
|
||||||
const child = build.action(undefined, opts);
|
const child = await build.action(undefined, opts);
|
||||||
const testPaths = await glob(join(FLECKS_CORE_ROOT, 'test/*.js'));
|
const testPaths = await glob(join(FLECKS_CORE_ROOT, 'test/*.js'));
|
||||||
if (0 === testPaths.length) {
|
if (0 === testPaths.length) {
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
|
@ -71,6 +71,7 @@ export default (program, flecks) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
require('@flecks/core/build/stub')(flecks.stubs);
|
||||||
if (!watch) {
|
if (!watch) {
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
child.on('exit', (code) => {
|
child.on('exit', (code) => {
|
|
@ -1,10 +1,10 @@
|
||||||
const flecksConfigFn = require('@flecks/core/server/build/webpack.config');
|
const flecksConfigFn = require('@flecks/core/build/fleck.webpack.config');
|
||||||
|
|
||||||
const ProcessAssets = require('./process-assets');
|
const ProcessAssets = require('./process-assets');
|
||||||
|
|
||||||
module.exports = async (env, argv, flecks) => {
|
module.exports = async (env, argv, flecks) => {
|
||||||
const config = await flecksConfigFn(env, argv, flecks);
|
const config = await flecksConfigFn(env, argv, flecks);
|
||||||
config.plugins.push(new ProcessAssets(flecks));
|
config.plugins.push(new ProcessAssets(flecks));
|
||||||
config.stats = flecks.get('@flecks/fleck/server.stats');
|
config.stats = flecks.get('@flecks/fleck.stats');
|
||||||
return config;
|
return config;
|
||||||
};
|
};
|
|
@ -1,14 +1,14 @@
|
||||||
import {join} from 'path';
|
const {join} = require('path');
|
||||||
|
|
||||||
import {glob} from '@flecks/core/server';
|
const {glob} = require('@flecks/core/server');
|
||||||
|
|
||||||
import commands from './commands';
|
const commands = require('./commands');
|
||||||
|
|
||||||
const {
|
const {
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
FLECKS_CORE_ROOT = process.cwd(),
|
||||||
} = process.env;
|
} = process.env;
|
||||||
|
|
||||||
export const hooks = {
|
exports.hooks = {
|
||||||
'@flecks/core.commands': commands,
|
'@flecks/core.commands': commands,
|
||||||
'@flecks/core.config': () => ({
|
'@flecks/core.config': () => ({
|
||||||
/**
|
/**
|
||||||
|
@ -20,20 +20,24 @@ export const hooks = {
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
'@flecks/core.targets': () => ['fleck'],
|
'@flecks/core.targets': () => ['fleck'],
|
||||||
'@flecks/fleck/server.processAssets': async (assets, compilation, flecks) => {
|
'@flecks/fleck.processAssets': async (assets, compilation, flecks) => {
|
||||||
const {RawSource} = compilation.compiler.webpack.sources;
|
const {RawSource} = compilation.compiler.webpack.sources;
|
||||||
const packageJson = assets['package.json'];
|
const packageJson = assets['package.json'];
|
||||||
const json = JSON.parse(packageJson.source().toString());
|
const json = JSON.parse(packageJson.source().toString());
|
||||||
const {files} = json;
|
const {files} = json;
|
||||||
// Add defaults.
|
// Add defaults.
|
||||||
files.push('build', 'src');
|
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.
|
// Add tests if they exist.
|
||||||
const testFiles = await glob(join(FLECKS_CORE_ROOT, 'test/*.js'));
|
const testFiles = await glob(join(FLECKS_CORE_ROOT, 'test/**/*.js'));
|
||||||
if (testFiles.length > 0) {
|
if (testFiles.length > 0) {
|
||||||
files.push('test', 'test.js');
|
files.push('test', 'test.js');
|
||||||
}
|
}
|
||||||
// Let others have a say.
|
// Let others have a say.
|
||||||
await flecks.invokeSequentialAsync('@flecks/fleck/server.packageJson', json, compilation);
|
await flecks.invokeSequentialAsync('@flecks/fleck.packageJson', json, compilation);
|
||||||
// Add any sourcemaps.
|
// Add any sourcemaps.
|
||||||
json.files = json.files
|
json.files = json.files
|
||||||
.map((filename) => {
|
.map((filename) => {
|
|
@ -1,2 +1,2 @@
|
||||||
'@flecks/core': {}
|
'@flecks/core': {}
|
||||||
'@flecks/fleck:./src': {}
|
'@flecks/fleck:.': {}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user