refactor: explication
This commit is contained in:
parent
85958c2d87
commit
f657c5ea8b
2
.vscode/settings.json
vendored
2
.vscode/settings.json
vendored
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"eslint.workingDirectories": [{"pattern": "./packages/*"}],
|
"eslint.workingDirectories": [{"pattern": "./packages/*"}],
|
||||||
"eslint.options": {"overrideConfigFile": "./node_modules/@flecks/build/build/eslint.config.js"},
|
"eslint.options": {"overrideConfigFile": "../build/dist/build/eslint.config.js"},
|
||||||
}
|
}
|
|
@ -10,6 +10,7 @@ module.exports = (api) => {
|
||||||
setSpreadProperties: true,
|
setSpreadProperties: true,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
|
'@babel/plugin-syntax-dynamic-import',
|
||||||
'@babel/plugin-syntax-class-properties',
|
'@babel/plugin-syntax-class-properties',
|
||||||
'@babel/plugin-syntax-logical-assignment-operators',
|
'@babel/plugin-syntax-logical-assignment-operators',
|
||||||
'@babel/plugin-syntax-nullish-coalescing-operator',
|
'@babel/plugin-syntax-nullish-coalescing-operator',
|
||||||
|
@ -24,6 +25,11 @@ module.exports = (api) => {
|
||||||
'@babel/plugin-transform-async-to-generator',
|
'@babel/plugin-transform-async-to-generator',
|
||||||
'@babel/plugin-transform-object-super',
|
'@babel/plugin-transform-object-super',
|
||||||
],
|
],
|
||||||
|
shippedProposals: true,
|
||||||
|
targets: {
|
||||||
|
esmodules: true,
|
||||||
|
node: 'current',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
const {realpath} = require('fs/promises');
|
const {join} = require('path');
|
||||||
const {dirname, join, relative} = require('path');
|
|
||||||
|
|
||||||
const D = require('@flecks/core/build/debug');
|
const D = require('@flecks/core/build/debug');
|
||||||
const {Flecks} = require('@flecks/core/build/flecks');
|
const {Flecks} = require('@flecks/core/build/flecks');
|
||||||
|
@ -65,31 +64,18 @@ module.exports = class Build extends Flecks {
|
||||||
roots = {};
|
roots = {};
|
||||||
|
|
||||||
async babel() {
|
async babel() {
|
||||||
const merging = [
|
return babelmerge.all([
|
||||||
{
|
{configFile: await this.resolveBuildConfig('babel.config.js')},
|
||||||
plugins: ['@babel/plugin-syntax-dynamic-import'],
|
...this.invokeFlat('@flecks/core.babel'),
|
||||||
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 = {}) {
|
static async buildRuntime(originalConfig, platforms, flecks = {}) {
|
||||||
const dealiasedConfig = Object.fromEntries(
|
const cleanConfig = JSON.parse(JSON.stringify(originalConfig));
|
||||||
Object.entries(originalConfig)
|
// Dealias the config keys.
|
||||||
|
const dealiasedConfig = environmentConfiguration(
|
||||||
|
Object.fromEntries(
|
||||||
|
Object.entries(cleanConfig)
|
||||||
.map(([maybeAliasedPath, config]) => {
|
.map(([maybeAliasedPath, config]) => {
|
||||||
const index = maybeAliasedPath.indexOf(':');
|
const index = maybeAliasedPath.indexOf(':');
|
||||||
return [
|
return [
|
||||||
|
@ -97,110 +83,25 @@ module.exports = class Build extends Flecks {
|
||||||
config,
|
config,
|
||||||
];
|
];
|
||||||
}),
|
}),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
const resolver = new Resolver();
|
const resolver = new Resolver({root: FLECKS_CORE_ROOT});
|
||||||
const explication = await explicate(
|
const {paths, roots} = await explicate({
|
||||||
Object.keys(originalConfig),
|
paths: Object.keys(originalConfig),
|
||||||
{
|
|
||||||
platforms,
|
platforms,
|
||||||
resolver,
|
resolver,
|
||||||
root: FLECKS_CORE_ROOT,
|
|
||||||
importer: (request) => require(request),
|
importer: (request) => require(request),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
const runtime = {
|
const runtime = {
|
||||||
config: environmentConfiguration(
|
config: Object.fromEntries(paths.map((path) => [path, dealiasedConfig[path] || {}])),
|
||||||
Object.fromEntries(
|
flecks: Object.fromEntries(paths.map((path) => [
|
||||||
Object.values(explication.descriptors)
|
path,
|
||||||
.map(({path}) => [path, dealiasedConfig[path] || {}]),
|
flecks[path] || roots[path]?.bootstrap || {},
|
||||||
),
|
])),
|
||||||
),
|
|
||||||
flecks: Object.fromEntries(
|
|
||||||
Object.values(explication.descriptors)
|
|
||||||
.map(({path, request}) => [path, flecks[path] || explication.roots[request] || {}]),
|
|
||||||
),
|
|
||||||
};
|
};
|
||||||
const aliased = {};
|
|
||||||
const compiled = {};
|
|
||||||
const reverseRequest = Object.fromEntries(
|
|
||||||
Object.entries(explication.descriptors)
|
|
||||||
.map(([, {path, request}]) => [request, path]),
|
|
||||||
);
|
|
||||||
const roots = Object.fromEntries(
|
|
||||||
(await Promise.all(Object.entries(explication.roots)
|
|
||||||
.map(async ([request, bootstrap]) => {
|
|
||||||
const packageRequest = await realpath(await resolver.resolve(join(request, 'package.json')));
|
|
||||||
const realDirname = dirname(packageRequest);
|
|
||||||
const {dependencies = {}, devDependencies = {}} = require(packageRequest);
|
|
||||||
let source;
|
|
||||||
let root;
|
|
||||||
// One of ours?
|
|
||||||
if (
|
|
||||||
[].concat(
|
|
||||||
Object.keys(dependencies),
|
|
||||||
Object.keys(devDependencies),
|
|
||||||
)
|
|
||||||
.includes('@flecks/fleck')
|
|
||||||
) {
|
|
||||||
root = realDirname.endsWith('/dist') ? realDirname.slice(0, -5) : realDirname;
|
|
||||||
source = join(root, 'src');
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
root = realDirname;
|
|
||||||
source = realDirname;
|
|
||||||
}
|
|
||||||
return [
|
|
||||||
reverseRequest[request],
|
|
||||||
{
|
|
||||||
bootstrap,
|
|
||||||
request,
|
|
||||||
root,
|
|
||||||
source,
|
|
||||||
},
|
|
||||||
];
|
|
||||||
})))
|
|
||||||
// Reverse sort for greedy root matching.
|
|
||||||
.sort(([l], [r]) => (l < r ? 1 : -1)),
|
|
||||||
);
|
|
||||||
await Promise.all(
|
|
||||||
Object.entries(explication.descriptors)
|
|
||||||
.map(async ([, {path, request}]) => {
|
|
||||||
if (path !== request) {
|
|
||||||
aliased[path] = request;
|
|
||||||
}
|
|
||||||
const [root, requestRoot] = Object.entries(roots)
|
|
||||||
.find(([, {request: rootRequest}]) => request.startsWith(rootRequest)) || [];
|
|
||||||
if (requestRoot && compiled[requestRoot.root]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
let resolvedRequest = await resolver.resolve(request);
|
|
||||||
if (!resolvedRequest) {
|
|
||||||
if (!requestRoot) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
resolvedRequest = await resolver.resolve(join(requestRoot.root, 'package.json'));
|
|
||||||
}
|
|
||||||
const realResolvedRequest = await realpath(resolvedRequest);
|
|
||||||
if (path !== request || resolvedRequest !== realResolvedRequest) {
|
|
||||||
if (requestRoot) {
|
|
||||||
if (!compiled[requestRoot.root]) {
|
|
||||||
compiled[requestRoot.root] = {
|
|
||||||
flecks: [],
|
|
||||||
path: root,
|
|
||||||
root: requestRoot.root,
|
|
||||||
source: requestRoot.source,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
compiled[requestRoot.root].flecks.push(path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
aliased,
|
|
||||||
compiled,
|
|
||||||
resolver,
|
resolver,
|
||||||
roots,
|
roots: Object.entries(roots).map(([path, {request}]) => [path, request]),
|
||||||
runtime,
|
runtime,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -225,15 +126,11 @@ module.exports = class Build extends Flecks {
|
||||||
debug('bootstrap configuration (%s)', configType);
|
debug('bootstrap configuration (%s)', configType);
|
||||||
debugSilly(originalConfig);
|
debugSilly(originalConfig);
|
||||||
const {
|
const {
|
||||||
aliased,
|
|
||||||
compiled,
|
|
||||||
resolver,
|
resolver,
|
||||||
roots,
|
roots,
|
||||||
runtime,
|
runtime,
|
||||||
} = await this.buildRuntime(originalConfig, platforms, configFlecks);
|
} = await this.buildRuntime(originalConfig, platforms, configFlecks);
|
||||||
const flecks = super.from(runtime);
|
const flecks = super.from(runtime);
|
||||||
flecks.aliased = aliased;
|
|
||||||
flecks.compiled = compiled;
|
|
||||||
flecks.platforms = platforms;
|
flecks.platforms = platforms;
|
||||||
flecks.roots = roots;
|
flecks.roots = roots;
|
||||||
flecks.resolver = resolver;
|
flecks.resolver = resolver;
|
||||||
|
@ -255,7 +152,7 @@ module.exports = class Build extends Flecks {
|
||||||
return Object.fromEntries(
|
return Object.fromEntries(
|
||||||
Object.entries(this.config)
|
Object.entries(this.config)
|
||||||
.map(([path, config]) => {
|
.map(([path, config]) => {
|
||||||
const alias = this.aliased[path];
|
const alias = this.resolver.fallbacks[path];
|
||||||
return [alias ? `${path}:${alias}` : path, config];
|
return [alias ? `${path}:${alias}` : path, config];
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -279,38 +176,15 @@ module.exports = class Build extends Flecks {
|
||||||
return this.resolver.resolve(join(fleck, 'build', config));
|
return this.resolver.resolve(join(fleck, 'build', config));
|
||||||
}
|
}
|
||||||
|
|
||||||
async runtimeCompiler(runtime, config, {additionalModuleDirs = [], allowlist = []} = {}) {
|
async runtimeCompiler(runtime, config) {
|
||||||
// Compile?
|
// Compile?
|
||||||
const needCompilation = Object.entries(this.compiled);
|
const compiled = this.roots.filter(([path, request]) => path !== request);
|
||||||
if (needCompilation.length > 0) {
|
if (compiled.length > 0) {
|
||||||
const babelConfig = await this.babel();
|
const include = Object.values(this.resolver.aliases);
|
||||||
const includes = [];
|
|
||||||
// Alias and de-externalize.
|
|
||||||
await Promise.all(
|
|
||||||
needCompilation
|
|
||||||
.map(async ([
|
|
||||||
root,
|
|
||||||
{
|
|
||||||
path,
|
|
||||||
source,
|
|
||||||
},
|
|
||||||
]) => {
|
|
||||||
allowlist.push(new RegExp(`^${path}`));
|
|
||||||
debugSilly('%s runtime de-externalized %s, alias: %s', runtime, root, source || path);
|
|
||||||
// Alias.
|
|
||||||
config.resolve.alias[path] = source || path;
|
|
||||||
// Root aliases.
|
|
||||||
config.resolve.fallback[path] = root;
|
|
||||||
config.resolve.modules.push(relative(FLECKS_CORE_ROOT, join(root, 'node_modules')));
|
|
||||||
additionalModuleDirs.push(relative(FLECKS_CORE_ROOT, join(root, 'node_modules')));
|
|
||||||
includes.push(root);
|
|
||||||
}),
|
|
||||||
);
|
|
||||||
// Compile.
|
|
||||||
config.module.rules.push(
|
config.module.rules.push(
|
||||||
{
|
{
|
||||||
test: /\.(m?jsx?)?$/,
|
test: /\.(m?jsx?)?$/,
|
||||||
include: includes,
|
include,
|
||||||
use: [
|
use: [
|
||||||
{
|
{
|
||||||
loader: require.resolve('babel-loader'),
|
loader: require.resolve('babel-loader'),
|
||||||
|
@ -318,35 +192,30 @@ module.exports = class Build extends Flecks {
|
||||||
cacheDirectory: true,
|
cacheDirectory: true,
|
||||||
babelrc: false,
|
babelrc: false,
|
||||||
configFile: false,
|
configFile: false,
|
||||||
...babelConfig,
|
...await this.babel(),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// Aliases.
|
|
||||||
Object.entries(this.aliased)
|
|
||||||
.forEach(([from, to]) => {
|
|
||||||
if (
|
|
||||||
!Object.entries(this.compiled)
|
|
||||||
.some(([, {flecks}]) => flecks.includes(from))
|
|
||||||
) {
|
|
||||||
config.resolve.alias[from] = to;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Our very own lil' chunk.
|
// Our very own lil' chunk.
|
||||||
Flecks.set(config, 'optimization.splitChunks.cacheGroups.flecks-compiled', {
|
Flecks.set(config, 'optimization.splitChunks.cacheGroups.flecks-compiled', {
|
||||||
chunks: 'all',
|
chunks: 'all',
|
||||||
enforce: true,
|
enforce: true,
|
||||||
priority: 100,
|
priority: 100,
|
||||||
test: new RegExp(
|
test: new RegExp(`(?:${
|
||||||
`(?:${
|
include.map((path) => path.replace(/[\\/]/g, '[\\/]')).join('|')
|
||||||
includes
|
})`),
|
||||||
.map((path) => path.replace(/[\\/]/g, '[\\/]')).join('|')
|
|
||||||
})`,
|
|
||||||
),
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// Resolution.
|
||||||
|
const {resolve, resolveLoader} = config;
|
||||||
|
resolve.alias = {...resolve.alias, ...this.resolver.aliases};
|
||||||
|
resolve.fallback = {...resolve.fallback, ...this.resolver.fallbacks};
|
||||||
|
resolve.modules = [...resolve.modules, ...this.resolver.modules];
|
||||||
|
resolveLoader.alias = {...resolveLoader.alias, ...this.resolver.aliases};
|
||||||
|
resolveLoader.fallback = {...resolveLoader.fallback, ...this.resolver.fallbacks};
|
||||||
|
resolveLoader.modules = [...resolveLoader.modules, ...this.resolver.modules];
|
||||||
}
|
}
|
||||||
|
|
||||||
get stubs() {
|
get stubs() {
|
||||||
|
|
|
@ -9,7 +9,7 @@ module.exports = async (env, argv) => {
|
||||||
config.plugins.push(new ProcessAssets('fleck', flecks));
|
config.plugins.push(new ProcessAssets('fleck', flecks));
|
||||||
// Small hack because internals.
|
// Small hack because internals.
|
||||||
flecks.hooks['@flecks/build.processAssets'] = [{
|
flecks.hooks['@flecks/build.processAssets'] = [{
|
||||||
hook: '@flecks/build',
|
fleck: '@flecks/build',
|
||||||
fn: (target, assets, compilation) => processFleckAssets(assets, compilation),
|
fn: (target, assets, compilation) => processFleckAssets(assets, compilation),
|
||||||
}];
|
}];
|
||||||
config.plugins.push(executable());
|
config.plugins.push(executable());
|
||||||
|
|
|
@ -1,159 +1,127 @@
|
||||||
const {join, relative, resolve} = require('path');
|
const {access, realpath} = require('fs/promises');
|
||||||
|
const {Module} = require('module');
|
||||||
const {
|
const {
|
||||||
FLECKS_CORE_ROOT = process.cwd(),
|
delimiter,
|
||||||
} = process.env;
|
join,
|
||||||
|
resolve,
|
||||||
|
} = require('path');
|
||||||
|
|
||||||
module.exports = async function explicate(
|
module.exports = async function explicate(
|
||||||
maybeAliasedPaths,
|
|
||||||
{
|
{
|
||||||
importer,
|
importer,
|
||||||
|
paths: maybeAliasedPaths,
|
||||||
platforms = ['server'],
|
platforms = ['server'],
|
||||||
resolver,
|
resolver,
|
||||||
root,
|
|
||||||
},
|
},
|
||||||
) {
|
) {
|
||||||
const descriptors = {};
|
const dependentPaths = [];
|
||||||
const seen = {};
|
|
||||||
const roots = {};
|
const roots = {};
|
||||||
function createDescriptor(maybeAliasedPath) {
|
async function addRoot(path, request) {
|
||||||
const index = maybeAliasedPath.indexOf(':');
|
// Already added it?
|
||||||
return -1 === index
|
if (Object.keys(roots).some((rootPath) => path.startsWith(rootPath))) {
|
||||||
? {
|
|
||||||
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;
|
return;
|
||||||
}
|
}
|
||||||
descriptors[request] = descriptor;
|
|
||||||
}
|
|
||||||
async function getRootDescriptor(descriptor) {
|
|
||||||
const {path, request} = descriptor;
|
|
||||||
// Walk up and find the root, if any.
|
// Walk up and find the root, if any.
|
||||||
const pathParts = path.split('/');
|
const pathParts = path.split('/');
|
||||||
const requestParts = request.split('/');
|
const requestParts = path === request
|
||||||
let rootDescriptor;
|
? pathParts.slice()
|
||||||
|
: resolve(resolver.root, request).split('/');
|
||||||
|
/* eslint-disable no-await-in-loop */
|
||||||
while (pathParts.length > 0 && requestParts.length > 0) {
|
while (pathParts.length > 0 && requestParts.length > 0) {
|
||||||
const candidate = requestParts.join('/');
|
const candidate = requestParts.join('/');
|
||||||
// eslint-disable-next-line no-await-in-loop
|
|
||||||
if (await resolver.resolve(join(candidate, 'package.json'))) {
|
if (await resolver.resolve(join(candidate, 'package.json'))) {
|
||||||
rootDescriptor = {
|
const rootPath = pathParts.join('/');
|
||||||
path: pathParts.join('/'),
|
// Don't add the root if this path doesn't actually exist.
|
||||||
request: requestParts.join('/'),
|
if (path !== rootPath && !await resolver.resolve(path)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// Resolve symlinks.
|
||||||
|
let realCandidate;
|
||||||
|
try {
|
||||||
|
realCandidate = await realpath(candidate);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
realCandidate = candidate;
|
||||||
|
}
|
||||||
|
// Aliased or symlinked? Include submodules.
|
||||||
|
if (path !== request || realCandidate !== candidate) {
|
||||||
|
const submodules = join(realCandidate, 'node_modules');
|
||||||
|
resolver.addModules(submodules);
|
||||||
|
// Runtime NODE_PATH hacking.
|
||||||
|
const {env} = process;
|
||||||
|
env.NODE_PATH = (env.NODE_PATH || '') + delimiter + submodules;
|
||||||
|
// eslint-disable-next-line no-underscore-dangle
|
||||||
|
Module._initPaths();
|
||||||
|
}
|
||||||
|
// Load `bootstrap.js`.
|
||||||
|
const bootstrapPath = await resolver.resolve(join(candidate, 'build', 'flecks.bootstrap'));
|
||||||
|
const bootstrap = bootstrapPath ? importer(bootstrapPath) : {};
|
||||||
|
// First add dependencies.
|
||||||
|
const {dependencies = []} = bootstrap;
|
||||||
|
if (dependencies.length > 0) {
|
||||||
|
await Promise.all(dependencies.map((dependency) => addRoot(dependency, dependency)));
|
||||||
|
dependentPaths.push(...dependencies);
|
||||||
|
}
|
||||||
|
// Add root as a dependency.
|
||||||
|
dependentPaths.push(rootPath);
|
||||||
|
// Add root.
|
||||||
|
roots[rootPath] = {
|
||||||
|
bootstrap,
|
||||||
|
request: realCandidate !== candidate ? realCandidate : candidate,
|
||||||
};
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pathParts.pop();
|
pathParts.pop();
|
||||||
requestParts.pop();
|
requestParts.pop();
|
||||||
}
|
}
|
||||||
return rootDescriptor;
|
/* eslint-enable no-await-in-loop */
|
||||||
}
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
let descriptorRequest = descriptor.request;
|
|
||||||
if (areDescriptorsTheSame) {
|
|
||||||
descriptorRequest = join(descriptorRequest, 'src');
|
|
||||||
}
|
|
||||||
if (descriptor.path !== descriptor.request) {
|
|
||||||
resolver.addAlias(descriptor.path, descriptorRequest);
|
|
||||||
if (descriptorRequest !== descriptor.request) {
|
|
||||||
resolver.addFallback(descriptor.path, descriptor.request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await Promise.all(
|
|
||||||
platforms
|
|
||||||
.filter((platform) => !platform.startsWith('!'))
|
|
||||||
.map(async (platform) => {
|
|
||||||
if (await resolver.resolve(join(descriptor.request, platform))) {
|
|
||||||
const [path, request] = [
|
|
||||||
join(descriptor.path, platform),
|
|
||||||
join(descriptor.request, platform),
|
|
||||||
];
|
|
||||||
await doExplication({path, request});
|
|
||||||
if (path !== request) {
|
|
||||||
resolver.addAlias(path, request);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (await resolver.resolve(join(descriptorRequest, 'src', platform))) {
|
|
||||||
const [path, request] = [
|
|
||||||
join(descriptor.path, platform),
|
|
||||||
join(descriptorRequest, 'src', platform),
|
|
||||||
];
|
|
||||||
await doExplication({path, request});
|
|
||||||
if (path !== request) {
|
|
||||||
resolver.addAlias(path, request);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Normalize maybe aliased paths into path and request.
|
||||||
|
const normalized = await Promise.all(
|
||||||
|
maybeAliasedPaths.map(async (maybeAliasedPath) => {
|
||||||
|
const index = maybeAliasedPath.indexOf(':');
|
||||||
|
return -1 === index
|
||||||
|
? [maybeAliasedPath, maybeAliasedPath]
|
||||||
|
: [maybeAliasedPath.slice(0, index), maybeAliasedPath.slice(index + 1)];
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
// Add roots.
|
||||||
async function explicateRoot(descriptor) {
|
await Promise.all(normalized.map(([path, request]) => addRoot(path, request)));
|
||||||
// Walk up and find the root, if any.
|
// Add aliases and fallbacks.
|
||||||
const rootDescriptor = await getRootDescriptor(descriptor);
|
|
||||||
if (!rootDescriptor || roots[rootDescriptor.request]) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const {path, request} = rootDescriptor;
|
|
||||||
if (path !== request) {
|
|
||||||
resolver.addModules(relative(FLECKS_CORE_ROOT, join(request, 'node_modules')));
|
|
||||||
}
|
|
||||||
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(
|
await Promise.all(
|
||||||
dependencies
|
Object.entries(roots)
|
||||||
.map(createDescriptor)
|
.filter(([path, {request}]) => path !== request)
|
||||||
.map(explicateDescriptor),
|
.map(async ([path, {request}]) => {
|
||||||
|
try {
|
||||||
|
await access(join(request, 'src'));
|
||||||
|
resolver.addAlias(path, join(request, 'src'));
|
||||||
|
}
|
||||||
|
// eslint-disable-next-line no-empty
|
||||||
|
catch (error) {}
|
||||||
|
resolver.addFallback(path, request);
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
const paths = (
|
||||||
await explicateDescriptor(rootDescriptor);
|
// Resolve dependent, normalized, and platform paths.
|
||||||
}
|
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
maybeAliasedPaths
|
dependentPaths.map((path) => [path, path])
|
||||||
.map(createDescriptor)
|
.concat(normalized)
|
||||||
.map(explicateDescriptor),
|
.map(([path]) => path)
|
||||||
);
|
.reduce((platformed, path) => (
|
||||||
return {
|
platformed.concat([path], platforms.map((platform) => join(path, platform)))
|
||||||
descriptors,
|
), [])
|
||||||
roots,
|
.map(async (path) => [path, await resolver.resolve(path)]),
|
||||||
};
|
)
|
||||||
|
)
|
||||||
|
// Filter unresolved except roots.
|
||||||
|
.filter(([path, resolved]) => resolved || roots[path])
|
||||||
|
.map(([path]) => path)
|
||||||
|
// Filter excluded platforms.
|
||||||
|
.filter((path) => (
|
||||||
|
!platforms
|
||||||
|
.filter((platform) => platform.startsWith('!'))
|
||||||
|
.map((platform) => platform.slice(1))
|
||||||
|
.some((excluded) => path.endsWith(`/${excluded}`))
|
||||||
|
));
|
||||||
|
return {paths: [...new Set(paths)], roots};
|
||||||
};
|
};
|
||||||
|
|
|
@ -20,7 +20,7 @@ exports.hooks = {
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (Object.entries(flecks.compiled).length > 0) {
|
if (flecks.roots.some(([path, request]) => path !== request)) {
|
||||||
config.resolve.symlinks = false;
|
config.resolve.symlinks = false;
|
||||||
}
|
}
|
||||||
config.plugins.push(new ProcessAssets(target, flecks));
|
config.plugins.push(new ProcessAssets(target, flecks));
|
||||||
|
|
27
packages/build/build/resolve.js
Normal file
27
packages/build/build/resolve.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
const Resolver = require('./resolver');
|
||||||
|
|
||||||
|
module.exports = function resolve({aliases, fallbacks}, stubs) {
|
||||||
|
const {Module} = require('module');
|
||||||
|
const {require: Mr} = Module.prototype;
|
||||||
|
const resolver = new Resolver({aliases, fallbacks, useSyncFileSystemCalls: true});
|
||||||
|
Module.prototype.require = function hackedRequire(request, options) {
|
||||||
|
for (let i = 0; i < stubs.length; ++i) {
|
||||||
|
if (request.startsWith(stubs[i])) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
return Mr.call(this, request, options);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
if (!error.message.startsWith('Cannot find module')) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
const resolved = resolver.resolveSync(request);
|
||||||
|
if (!resolved) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return Mr.call(this, resolved, options);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
|
@ -22,18 +22,29 @@ const nodeFileSystem = new CachedInputFileSystem(fs, 4000);
|
||||||
|
|
||||||
module.exports = class Resolver {
|
module.exports = class Resolver {
|
||||||
|
|
||||||
constructor(options) {
|
constructor(options = {}) {
|
||||||
|
const {
|
||||||
|
modules = [join(FLECKS_CORE_ROOT, 'node_modules'), 'node_modules'],
|
||||||
|
root = FLECKS_CORE_ROOT,
|
||||||
|
...rest
|
||||||
|
} = options;
|
||||||
this.resolver = ResolverFactory.createResolver({
|
this.resolver = ResolverFactory.createResolver({
|
||||||
conditionNames: ['node'],
|
conditionNames: ['node'],
|
||||||
extensions: ['.js', '.json', '.node'],
|
extensions: ['.js', '.json', '.node'],
|
||||||
fileSystem: nodeFileSystem,
|
fileSystem: nodeFileSystem,
|
||||||
|
modules,
|
||||||
symlinks: false,
|
symlinks: false,
|
||||||
...options,
|
...rest,
|
||||||
});
|
});
|
||||||
|
this.aliases = {};
|
||||||
|
this.fallbacks = {};
|
||||||
|
this.modules = modules;
|
||||||
|
this.root = root;
|
||||||
}
|
}
|
||||||
|
|
||||||
addAlias(name, alias) {
|
addAlias(name, alias) {
|
||||||
debugSilly("adding alias: '%s' -> '%s'", name, alias);
|
debugSilly("adding alias: '%s' -> '%s'", name, alias);
|
||||||
|
this.aliases[name] = alias;
|
||||||
new AliasPlugin(
|
new AliasPlugin(
|
||||||
'raw-resolve',
|
'raw-resolve',
|
||||||
{name, onlyModule: false, alias},
|
{name, onlyModule: false, alias},
|
||||||
|
@ -50,6 +61,7 @@ module.exports = class Resolver {
|
||||||
|
|
||||||
addFallback(name, alias) {
|
addFallback(name, alias) {
|
||||||
debugSilly("adding fallback: '%s' -> '%s'", name, alias);
|
debugSilly("adding fallback: '%s' -> '%s'", name, alias);
|
||||||
|
this.fallbacks[name] = alias;
|
||||||
new AliasPlugin(
|
new AliasPlugin(
|
||||||
'described-resolve',
|
'described-resolve',
|
||||||
{name, onlyModule: false, alias},
|
{name, onlyModule: false, alias},
|
||||||
|
@ -59,10 +71,11 @@ module.exports = class Resolver {
|
||||||
|
|
||||||
addModules(path) {
|
addModules(path) {
|
||||||
debugSilly("adding modules: '%s'", path);
|
debugSilly("adding modules: '%s'", path);
|
||||||
|
this.modules.push(path);
|
||||||
new ModulesInHierarchicalDirectoriesPlugin(
|
new ModulesInHierarchicalDirectoriesPlugin(
|
||||||
"raw-module",
|
'raw-module',
|
||||||
path,
|
path,
|
||||||
"module"
|
'module',
|
||||||
).apply(this.resolver);
|
).apply(this.resolver);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +86,7 @@ module.exports = class Resolver {
|
||||||
async resolve(request) {
|
async resolve(request) {
|
||||||
try {
|
try {
|
||||||
return await new Promise((resolve, reject) => {
|
return await new Promise((resolve, reject) => {
|
||||||
this.resolver.resolve(nodeContext, FLECKS_CORE_ROOT, request, {}, (error, path) => {
|
this.resolver.resolve(nodeContext, this.root, request, {}, (error, path) => {
|
||||||
if (error) {
|
if (error) {
|
||||||
reject(error);
|
reject(error);
|
||||||
}
|
}
|
||||||
|
@ -91,4 +104,16 @@ module.exports = class Resolver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
resolveSync(request) {
|
||||||
|
try {
|
||||||
|
return this.resolver.resolveSync(nodeContext, this.root, request);
|
||||||
|
}
|
||||||
|
catch (error) {
|
||||||
|
if (!this.constructor.isResolutionError(error)) {
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -41,6 +41,12 @@ exports.defaultConfig = (flecks, specializedConfig) => {
|
||||||
},
|
},
|
||||||
plugins: [],
|
plugins: [],
|
||||||
resolve: {
|
resolve: {
|
||||||
|
alias: {},
|
||||||
|
extensions,
|
||||||
|
fallback: {},
|
||||||
|
modules: [],
|
||||||
|
},
|
||||||
|
resolveLoader: {
|
||||||
alias: {},
|
alias: {},
|
||||||
extensions,
|
extensions,
|
||||||
fallback: {},
|
fallback: {},
|
||||||
|
|
|
@ -12,69 +12,94 @@ const {
|
||||||
const root = join(FLECKS_CORE_ROOT, 'test', 'server', 'explicate');
|
const root = join(FLECKS_CORE_ROOT, 'test', 'server', 'explicate');
|
||||||
|
|
||||||
function createExplication(paths, platforms) {
|
function createExplication(paths, platforms) {
|
||||||
const resolver = new Resolver({modules: [join(root, 'fake_node_modules')]});
|
const resolver = new Resolver({
|
||||||
return explicate(
|
modules: [join(root, 'fake_node_modules')],
|
||||||
|
root,
|
||||||
|
});
|
||||||
|
return explicate({
|
||||||
paths,
|
paths,
|
||||||
{
|
|
||||||
platforms,
|
platforms,
|
||||||
resolver,
|
resolver,
|
||||||
root,
|
|
||||||
importer: (request) => __non_webpack_require__(request),
|
importer: (request) => __non_webpack_require__(request),
|
||||||
},
|
});
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
describe('explication', () => {
|
describe('explication', () => {
|
||||||
|
|
||||||
it('derives platforms', async () => {
|
it('derives platforms', async () => {
|
||||||
expect(Object.keys((await createExplication(['platformed'])).descriptors))
|
expect(await createExplication(['platformed']))
|
||||||
.to.deep.equal([
|
.to.deep.include({
|
||||||
'platformed', 'platformed/server',
|
paths: ['platformed', 'platformed/server'],
|
||||||
]);
|
});
|
||||||
expect(Object.keys((await createExplication(['server-only'])).descriptors))
|
expect(await createExplication(['server-only']))
|
||||||
.to.deep.equal([
|
.to.deep.include({
|
||||||
'server-only/server',
|
paths: ['server-only/server'],
|
||||||
]);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('derives through bootstrap', async () => {
|
it('derives through bootstrap', async () => {
|
||||||
expect(Object.keys((await createExplication(['real-root'])).descriptors))
|
expect(await createExplication(['real-root']))
|
||||||
.to.deep.equal([
|
.to.deep.include({
|
||||||
|
paths: [
|
||||||
'dependency', 'dependency/server',
|
'dependency', 'dependency/server',
|
||||||
'real-root', 'real-root/server',
|
'real-root', 'real-root/server',
|
||||||
]);
|
],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('excludes platforms', async () => {
|
it('excludes platforms', async () => {
|
||||||
expect(Object.keys(
|
expect(
|
||||||
(await createExplication(
|
await createExplication(
|
||||||
['platformed/client', 'dependency'],
|
['platformed/client', 'dependency'],
|
||||||
['server', '!client'],
|
['server', '!client'],
|
||||||
)).descriptors,
|
),
|
||||||
))
|
)
|
||||||
.to.deep.equal([
|
.to.deep.include({
|
||||||
'dependency', 'dependency/server',
|
paths: ['dependency', 'dependency/server'],
|
||||||
]);
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('explicates parents first', async () => {
|
it('explicates parents first', async () => {
|
||||||
expect(Object.keys((await createExplication(['real-root/server'])).descriptors))
|
expect(await createExplication(['real-root/server']))
|
||||||
.to.deep.equal([
|
.to.deep.include({
|
||||||
|
paths: [
|
||||||
'dependency', 'dependency/server',
|
'dependency', 'dependency/server',
|
||||||
'real-root', 'real-root/server',
|
'real-root', 'real-root/server',
|
||||||
]);
|
],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('explicates only bootstrapped', async () => {
|
it('explicates only bootstrapped', async () => {
|
||||||
expect(Object.keys((await createExplication(['only-bootstrapped'])).descriptors))
|
expect(await createExplication(['only-bootstrapped']))
|
||||||
.to.deep.equal([
|
.to.deep.include({
|
||||||
'only-bootstrapped',
|
paths: ['only-bootstrapped'],
|
||||||
]);
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('explicates root with src', async () => {
|
||||||
|
expect(await createExplication(['src-root:./src-root']))
|
||||||
|
.to.deep.include({
|
||||||
|
paths: ['src-root', 'src-root/server'],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('skips nonexistent', async () => {
|
it('skips nonexistent', async () => {
|
||||||
expect(await createExplication(['real-root/nonexistent']))
|
expect(await createExplication(['real-root/nonexistent']))
|
||||||
.to.deep.equal({descriptors: {}, roots: {}});
|
.to.deep.equal({paths: [], roots: {}});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('includes modules', async () => {
|
||||||
|
expect(await createExplication(['modules-root:./modules-root', 'foo']))
|
||||||
|
.to.deep.include({
|
||||||
|
paths: ['modules-root', 'foo'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('explicates aliased platforms', async () => {
|
||||||
|
expect(await createExplication(['aliased-platforms:./aliased-platforms']))
|
||||||
|
.to.deep.include({
|
||||||
|
paths: ['aliased-platforms', 'aliased-platforms/server'],
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
|
@ -0,0 +1 @@
|
||||||
|
{}
|
|
@ -8,7 +8,7 @@ module.exports = async (env, argv) => {
|
||||||
config.plugins.push(new ProcessAssets('fleck', flecks));
|
config.plugins.push(new ProcessAssets('fleck', flecks));
|
||||||
// Small hack because internals.
|
// Small hack because internals.
|
||||||
flecks.hooks['@flecks/build.processAssets'] = [{
|
flecks.hooks['@flecks/build.processAssets'] = [{
|
||||||
hook: '@flecks/build',
|
fleck: '@flecks/build',
|
||||||
fn: (target, assets, compilation) => processFleckAssets(assets, compilation),
|
fn: (target, assets, compilation) => processFleckAssets(assets, compilation),
|
||||||
}];
|
}];
|
||||||
return config;
|
return config;
|
||||||
|
|
|
@ -1,15 +0,0 @@
|
||||||
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,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"eslint.workingDirectories": [{"pattern": "./packages/*"}],
|
"eslint.workingDirectories": [{"pattern": "./packages/*"}],
|
||||||
"eslint.options": {"overrideConfigFile": "./node_modules/@flecks/build/build/eslint.config.js"},
|
"eslint.options": {"overrideConfigFile": "./node_modules/@flecks/build/build/eslint.config.js"}
|
||||||
}
|
}
|
|
@ -6,6 +6,7 @@
|
||||||
"build:only": "flecks build",
|
"build:only": "flecks build",
|
||||||
"debug": "DEBUG=@flecks/* npm run dev",
|
"debug": "DEBUG=@flecks/* npm run dev",
|
||||||
"dev": "npm run -- build:only -dh",
|
"dev": "npm run -- build:only -dh",
|
||||||
|
"postinstall": "patch-package",
|
||||||
"repl": "npx flecks repl --rlwrap",
|
"repl": "npx flecks repl --rlwrap",
|
||||||
"start": "DEBUG=@flecks/*,-*:silly npm run dev"
|
"start": "DEBUG=@flecks/*,-*:silly npm run dev"
|
||||||
},
|
},
|
||||||
|
|
|
@ -108,13 +108,13 @@ exports.parseSource = async (path, source) => {
|
||||||
return exports.parseNormalSource(path, source);
|
return exports.parseNormalSource(path, source);
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.parseFleckRoot = async (path, root) => (
|
exports.parseFleckRoot = async (request) => (
|
||||||
Promise.all(
|
Promise.all(
|
||||||
(await Promise.all([
|
(await Promise.all([
|
||||||
...await glob(join(root, 'src', '**', '*.js')),
|
...await glob(join(request, 'src', '**', '*.js')),
|
||||||
...await glob(join(root, 'build', '**', '*.js')),
|
...await glob(join(request, 'build', '**', '*.js')),
|
||||||
]))
|
]))
|
||||||
.map((filename) => [relative(root, filename), filename])
|
.map((filename) => [relative(request, filename), filename])
|
||||||
.map(async ([path, filename]) => {
|
.map(async ([path, filename]) => {
|
||||||
const buffer = await readFile(filename);
|
const buffer = await readFile(filename);
|
||||||
return [path, await exports.parseSource(path, buffer.toString('utf8'))];
|
return [path, await exports.parseSource(path, buffer.toString('utf8'))];
|
||||||
|
@ -124,7 +124,7 @@ exports.parseFleckRoot = async (path, root) => (
|
||||||
|
|
||||||
exports.parseFlecks = async (flecks) => (
|
exports.parseFlecks = async (flecks) => (
|
||||||
Promise.all(
|
Promise.all(
|
||||||
Object.entries(flecks.roots)
|
flecks.roots
|
||||||
.map(async ([path, {root}]) => [path, await exports.parseFleckRoot(path, root)]),
|
.map(async ([path, request]) => [path, await exports.parseFleckRoot(request)]),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -77,7 +77,7 @@ module.exports = (program, flecks) => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
require('@flecks/core/build/stub')(flecks.stubs);
|
require('@flecks/build/build/resolve')(flecks.resolver, flecks.stubs);
|
||||||
if (!watch) {
|
if (!watch) {
|
||||||
await new Promise((resolve, reject) => {
|
await new Promise((resolve, reject) => {
|
||||||
child.on('exit', (code) => {
|
child.on('exit', (code) => {
|
||||||
|
|
|
@ -2,6 +2,7 @@ const flecksConfigFn = require('@flecks/build/build/fleck.webpack.config');
|
||||||
|
|
||||||
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.resolve.modules.push('node_modules');
|
||||||
config.stats = flecks.get('@flecks/fleck.stats');
|
config.stats = flecks.get('@flecks/fleck.stats');
|
||||||
return config;
|
return config;
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
const {externals} = require('@flecks/build/server');
|
const {externals} = require('@flecks/build/server');
|
||||||
|
|
||||||
|
const D = require('@flecks/core/build/debug');
|
||||||
|
|
||||||
|
const debug = D('@flecks/server/build/runtime');
|
||||||
|
|
||||||
module.exports = async (config, env, argv, flecks) => {
|
module.exports = async (config, env, argv, flecks) => {
|
||||||
const runtimePath = await flecks.resolver.resolve('@flecks/server/runtime');
|
const runtimePath = await flecks.resolver.resolve('@flecks/server/runtime');
|
||||||
// Inject flecks configuration.
|
// Inject flecks configuration.
|
||||||
|
@ -10,6 +14,10 @@ module.exports = async (config, env, argv, flecks) => {
|
||||||
.filter(([, resolved]) => resolved)
|
.filter(([, resolved]) => resolved)
|
||||||
.map(([path]) => path);
|
.map(([path]) => path);
|
||||||
const runtime = {
|
const runtime = {
|
||||||
|
resolver: JSON.stringify({
|
||||||
|
aliases: flecks.resolver.aliases,
|
||||||
|
fallbacks: flecks.resolver.fallbacks,
|
||||||
|
}),
|
||||||
config: JSON.stringify(flecks.config),
|
config: JSON.stringify(flecks.config),
|
||||||
loadFlecks: [
|
loadFlecks: [
|
||||||
'async () => (',
|
'async () => (',
|
||||||
|
@ -98,14 +106,19 @@ module.exports = async (config, env, argv, flecks) => {
|
||||||
/^@babel\/runtime\/helpers\/esm/,
|
/^@babel\/runtime\/helpers\/esm/,
|
||||||
];
|
];
|
||||||
config.resolve.alias['@flecks/server/runtime$'] = runtimePath;
|
config.resolve.alias['@flecks/server/runtime$'] = runtimePath;
|
||||||
const nodeExternalsConfig = {
|
Object.entries(flecks.resolver.aliases).forEach(([path, request]) => {
|
||||||
allowlist,
|
debug('server runtime de-externalized %s, alias: %s', path, request);
|
||||||
};
|
allowlist.push(new RegExp(`^${path}`));
|
||||||
await flecks.runtimeCompiler('server', config, nodeExternalsConfig);
|
});
|
||||||
|
// Stubs.
|
||||||
|
flecks.stubs.forEach((stub) => {
|
||||||
|
config.resolve.alias[stub] = false;
|
||||||
|
});
|
||||||
|
await flecks.runtimeCompiler('server', config);
|
||||||
// Rewrite to signals for HMR.
|
// Rewrite to signals for HMR.
|
||||||
if ('production' !== argv.mode) {
|
if ('production' !== argv.mode) {
|
||||||
allowlist.push(/^webpack\/hot\/signal/);
|
allowlist.push(/^webpack\/hot\/signal/);
|
||||||
}
|
}
|
||||||
// Externalize the rest.
|
// Externalize the rest.
|
||||||
config.externals = externals(nodeExternalsConfig);
|
config.externals = externals({allowlist});
|
||||||
};
|
};
|
||||||
|
|
|
@ -50,7 +50,7 @@ module.exports = async (env, argv, flecks) => {
|
||||||
config.entry.index.push('@flecks/server/entry');
|
config.entry.index.push('@flecks/server/entry');
|
||||||
// Augment the application-starting configuration.
|
// Augment the application-starting configuration.
|
||||||
if (isStarting) {
|
if (isStarting) {
|
||||||
if (Object.entries(flecks.compiled).length > 0) {
|
if (flecks.roots.some(([path, request]) => path !== request)) {
|
||||||
nodeEnv.NODE_PRESERVE_SYMLINKS = 1;
|
nodeEnv.NODE_PRESERVE_SYMLINKS = 1;
|
||||||
}
|
}
|
||||||
config.plugins.push(
|
config.plugins.push(
|
||||||
|
|
|
@ -8,7 +8,7 @@ const {version} = require('../package.json');
|
||||||
|
|
||||||
(async () => {
|
(async () => {
|
||||||
const runtime = await __non_webpack_require__('@flecks/server/runtime');
|
const runtime = await __non_webpack_require__('@flecks/server/runtime');
|
||||||
const {loadFlecks, stubs} = runtime;
|
const {loadFlecks, resolver, stubs} = runtime;
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.log(`flecks server v${version}`);
|
console.log(`flecks server v${version}`);
|
||||||
try {
|
try {
|
||||||
|
@ -24,7 +24,7 @@ const {version} = require('../package.json');
|
||||||
const unserializedStubs = stubs.map((stub) => (Array.isArray(stub) ? new RegExp(...stub) : stub));
|
const unserializedStubs = stubs.map((stub) => (Array.isArray(stub) ? new RegExp(...stub) : stub));
|
||||||
if (unserializedStubs.length > 0) {
|
if (unserializedStubs.length > 0) {
|
||||||
debug('stubbing with %O', unserializedStubs);
|
debug('stubbing with %O', unserializedStubs);
|
||||||
__non_webpack_require__('@flecks/core/build/stub')(unserializedStubs);
|
__non_webpack_require__('@flecks/build/build/resolve')(resolver, unserializedStubs);
|
||||||
}
|
}
|
||||||
global.flecks = await Flecks.from({...runtime, flecks: await loadFlecks()});
|
global.flecks = await Flecks.from({...runtime, flecks: await loadFlecks()});
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -315,9 +315,3 @@ exports.hooks = {
|
||||||
return JSON.stringify(config);
|
return JSON.stringify(config);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
exports.stubs = {
|
|
||||||
server: [
|
|
||||||
/\.(c|s[ac])ss$/,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
|
|
|
@ -22,16 +22,12 @@ module.exports = async (config, env, argv, flecks) => {
|
||||||
Object.keys(flecks.flecks)
|
Object.keys(flecks.flecks)
|
||||||
.map(async (fleck) => {
|
.map(async (fleck) => {
|
||||||
// No root? How to infer?
|
// No root? How to infer?
|
||||||
const [root] = Object.entries(flecks.roots)
|
const [root, request] = flecks.roots.find(([root]) => fleck.startsWith(root)) || [];
|
||||||
.find(([root]) => fleck.startsWith(root)) || [];
|
|
||||||
if (!root) {
|
if (!root) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
// Compiled? It will be included with the compilation.
|
// Compiled? It will be included with the compilation.
|
||||||
if (
|
if (root !== request) {
|
||||||
Object.entries(flecks.compiled)
|
|
||||||
.some(([, {flecks}]) => flecks.includes(fleck))
|
|
||||||
) {
|
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
|
@ -96,12 +92,7 @@ module.exports = async (config, env, argv, flecks) => {
|
||||||
config.resolve.alias['@flecks/web/runtime$'] = runtime;
|
config.resolve.alias['@flecks/web/runtime$'] = runtime;
|
||||||
// Stubs.
|
// Stubs.
|
||||||
buildFlecks.stubs.forEach((stub) => {
|
buildFlecks.stubs.forEach((stub) => {
|
||||||
config.module.rules.push(
|
config.resolve.alias[stub] = false;
|
||||||
{
|
|
||||||
test: stub,
|
|
||||||
use: 'null-loader',
|
|
||||||
},
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
await buildFlecks.runtimeCompiler('web', config);
|
await buildFlecks.runtimeCompiler('web', config);
|
||||||
// Styles.
|
// Styles.
|
||||||
|
@ -109,26 +100,18 @@ module.exports = async (config, env, argv, flecks) => {
|
||||||
// Tests.
|
// Tests.
|
||||||
if (!isProduction) {
|
if (!isProduction) {
|
||||||
const testEntries = (await Promise.all(
|
const testEntries = (await Promise.all(
|
||||||
Object.entries(buildFlecks.roots)
|
buildFlecks.roots
|
||||||
.map(async ([parent, {request}]) => {
|
.map(async ([root, request]) => {
|
||||||
const tests = [];
|
const tests = [];
|
||||||
const resolved = dirname(await resolver.resolve(join(request, 'package.json')));
|
const rootTests = await glob(join(request, 'test', '*.js'));
|
||||||
const rootTests = await glob(join(resolved, 'test', '*.js'));
|
tests.push(...rootTests.map((test) => test.replace(request, root)));
|
||||||
tests.push(
|
|
||||||
...rootTests
|
|
||||||
.map((test) => test.replace(resolved, parent)),
|
|
||||||
);
|
|
||||||
const platformTests = await Promise.all(
|
const platformTests = await Promise.all(
|
||||||
buildFlecks.platforms.map((platform) => (
|
buildFlecks.platforms.map((platform) => (
|
||||||
glob(join(resolved, 'test', 'platforms', platform, '*.js'))
|
glob(join(request, 'test', platform, '*.js'))
|
||||||
)),
|
)),
|
||||||
);
|
);
|
||||||
tests.push(
|
tests.push(...platformTests.flat().map((test) => test.replace(request, root)));
|
||||||
...platformTests
|
return [root, tests];
|
||||||
.flat()
|
|
||||||
.map((test) => test.replace(resolved, parent)),
|
|
||||||
);
|
|
||||||
return [parent, tests];
|
|
||||||
}),
|
}),
|
||||||
))
|
))
|
||||||
.filter(([, tests]) => tests.length > 0);
|
.filter(([, tests]) => tests.length > 0);
|
||||||
|
|
|
@ -35,6 +35,7 @@ module.exports = async (env, argv, flecks) => {
|
||||||
stream: false,
|
stream: false,
|
||||||
util: require.resolve('util'),
|
util: require.resolve('util'),
|
||||||
},
|
},
|
||||||
|
modules: flecks.resolver.modules,
|
||||||
},
|
},
|
||||||
stats: {
|
stats: {
|
||||||
warningsFilter: [
|
warningsFilter: [
|
||||||
|
|
Loading…
Reference in New Issue
Block a user