feat: dynamic webpack :o
This commit is contained in:
parent
e49ef9b54c
commit
631106b29c
15
packages/core/hook/hook.avopack.js
Normal file
15
packages/core/hook/hook.avopack.js
Normal file
|
@ -0,0 +1,15 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = ({entries, paths, root, rules}) => {
|
||||
rules.push({
|
||||
test: new RegExp('@avocado/packages/core/hook/entry.js$'),
|
||||
use: {
|
||||
loader: '@avocado/core/hook/loader',
|
||||
options: {
|
||||
paths,
|
||||
root,
|
||||
},
|
||||
},
|
||||
});
|
||||
entries.push('@avocado/core/hook/entry');
|
||||
};
|
|
@ -1,7 +1,11 @@
|
|||
const path = require('path');
|
||||
|
||||
const glob = require('glob');
|
||||
const {getOptions} = require('loader-utils');
|
||||
const path = require('path');
|
||||
const validateOptions = require('schema-utils');
|
||||
|
||||
const {lookupSourcePaths} = require('../webpack/util');
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
|
@ -21,36 +25,19 @@ const schema = {
|
|||
module.exports = function(source) {
|
||||
const options = getOptions(this);
|
||||
// Validate schema.
|
||||
validateOptions(schema, options, 'Avocado hooks');
|
||||
validateOptions(schema, options, '[avocado] Hooks');
|
||||
// Extract options.
|
||||
const {paths} = options;
|
||||
// Search avocado.
|
||||
const avocadoPath = path.normalize(
|
||||
path.join(__dirname, '..', '..'),
|
||||
);
|
||||
paths.push(avocadoPath);
|
||||
// Get source paths.
|
||||
const sourcePaths = [];
|
||||
paths.forEach((path) => {
|
||||
const files = glob.sync(`${path}/**/hooks.js`, {
|
||||
follow: true,
|
||||
});
|
||||
sourcePaths.push(...files);
|
||||
});
|
||||
const {paths, root} = options;
|
||||
// Build registers.
|
||||
const sourcePaths = lookupSourcePaths(paths, 'hooks.js');
|
||||
const registers = sourcePaths.map((sourcePath) => {
|
||||
const relativePath = path.relative(__dirname, sourcePath);
|
||||
const basename = path.basename(relativePath, '.js');
|
||||
const relativePath = path.relative(root, sourcePath);
|
||||
const parts = relativePath.split('/');
|
||||
// Chop off basename.
|
||||
parts.pop();
|
||||
// Module or local?
|
||||
let importDirectory;
|
||||
if ('..' === parts[0]) {
|
||||
const avocadoPathParts = ['@avocado', 'core', 'hook'].concat(parts);
|
||||
importDirectory = path.normalize(avocadoPathParts.join('/'));
|
||||
}
|
||||
else if ('node_modules' === parts[0]) {
|
||||
if ('node_modules' === parts[0]) {
|
||||
importDirectory = parts.slice(1).join('/');
|
||||
}
|
||||
else {
|
||||
|
|
92
packages/core/webpack/autoreg.js
Normal file
92
packages/core/webpack/autoreg.js
Normal file
|
@ -0,0 +1,92 @@
|
|||
const path = require('path');
|
||||
|
||||
const glob = require('glob');
|
||||
const {getOptions} = require('loader-utils');
|
||||
const validateOptions = require('schema-utils');
|
||||
|
||||
const {lookupSourcePaths} = require('./util');
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
paths: {
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
type: 'array',
|
||||
},
|
||||
registrar: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
function: {
|
||||
type: 'string',
|
||||
},
|
||||
module: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
required: [
|
||||
'function',
|
||||
'module',
|
||||
],
|
||||
},
|
||||
type: {
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
required: [
|
||||
'registrar',
|
||||
'type',
|
||||
],
|
||||
};
|
||||
|
||||
// Dynamically require all traits.
|
||||
module.exports = function(source) {
|
||||
const options = getOptions(this);
|
||||
// Validate schema.
|
||||
validateOptions(schema, options, '[avocado] Autotomatic registration');
|
||||
// Extract options.
|
||||
const {classTransformer: transformer, paths, registrar, root, type} = options;
|
||||
// Search avocado.
|
||||
paths.push(path.resolve(
|
||||
__dirname, 'node_modules', '@avocado',
|
||||
));
|
||||
// Get all trait source paths.
|
||||
const sourcePaths = lookupSourcePaths(paths, `*.${type}.js`);
|
||||
// Build import definitions.
|
||||
const importDefinitions = sourcePaths.map((sourcePath) => {
|
||||
const relativePath = path.relative(root, sourcePath);
|
||||
const basename = path.basename(relativePath, `.${type}.js`);
|
||||
const parts = relativePath.split('/');
|
||||
// Chop off basename.
|
||||
parts.pop();
|
||||
// Module or local?
|
||||
let importDirectory;
|
||||
if ('node_modules' === parts[0]) {
|
||||
importDirectory = `${parts.slice(1).join('/')}`;
|
||||
}
|
||||
else {
|
||||
importDirectory = `${root}/${parts.join('/')}`
|
||||
}
|
||||
const importPath = `${importDirectory}/${basename}.${type}`;
|
||||
// Extract class name.
|
||||
const baseparts = basename.split('-');
|
||||
const className = baseparts.reduce((className, part) => {
|
||||
const firstLetter = part.charAt(0).toUpperCase();
|
||||
const rest = part.substr(1).toLowerCase();
|
||||
return className + firstLetter + rest;
|
||||
}, '');
|
||||
const transformed = transformer ? transformer(className) : className;
|
||||
// Import and register.
|
||||
return [
|
||||
`${registrar.function}(require('${importPath}').${transformed});`,
|
||||
].join('\n');
|
||||
});
|
||||
// Import trait registry first.
|
||||
const output = [
|
||||
`import {${registrar.function}} from '${registrar.module}'`,
|
||||
'',
|
||||
...importDefinitions
|
||||
].join('\n');
|
||||
return output;
|
||||
}
|
32
packages/core/webpack/loader.js
Normal file
32
packages/core/webpack/loader.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
const path = require('path');
|
||||
|
||||
const glob = require('glob');
|
||||
const {getOptions} = require('loader-utils');
|
||||
const validateOptions = require('schema-utils');
|
||||
|
||||
const {lookupSourcePaths} = require('../webpack/util');
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
entries: {
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
type: 'array',
|
||||
},
|
||||
},
|
||||
required: [
|
||||
'entries',
|
||||
],
|
||||
};
|
||||
|
||||
// Dynamically require all traits.
|
||||
module.exports = function(source) {
|
||||
const options = getOptions(this);
|
||||
validateOptions(schema, options, 'Avocado core');
|
||||
const {entries} = options;
|
||||
return entries.reduce((r, entry) => {
|
||||
return r + `import '${entry}';`;
|
||||
}, '');
|
||||
}
|
46
packages/core/webpack/plugin.js
Normal file
46
packages/core/webpack/plugin.js
Normal file
|
@ -0,0 +1,46 @@
|
|||
const path = require('path');
|
||||
|
||||
const {lookupSourcePaths} = require('./util');
|
||||
|
||||
exports.AvocadoPlugin = class AvocadoPlugin {
|
||||
|
||||
constructor(root, side) {
|
||||
this.root = root;
|
||||
this.side = side;
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
const {options} = compiler;
|
||||
const {module} = options;
|
||||
const entries = [
|
||||
'@babel/polyfill',
|
||||
];
|
||||
const paths = [
|
||||
path.resolve(this.root, 'common'),
|
||||
path.resolve(this.root, this.side),
|
||||
];
|
||||
const sourcePaths = lookupSourcePaths(paths, '*.avopack.js');
|
||||
sourcePaths.forEach((sourcePath) => {
|
||||
require(`${this.root}/${sourcePath}`)({
|
||||
compiler,
|
||||
entries,
|
||||
options,
|
||||
paths,
|
||||
root: this.root,
|
||||
rules: options.module.rules,
|
||||
side: this.side,
|
||||
});
|
||||
});
|
||||
module.rules.push({
|
||||
test: new RegExp('@avocado/packages/core/webpack/entry.js$'),
|
||||
use: {
|
||||
loader: '@avocado/core/webpack/loader',
|
||||
options: {
|
||||
entries,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
18
packages/core/webpack/util.js
Normal file
18
packages/core/webpack/util.js
Normal file
|
@ -0,0 +1,18 @@
|
|||
const path = require('path');
|
||||
|
||||
const glob = require('glob');
|
||||
|
||||
exports.lookupSourcePaths = function(paths, pattern) {
|
||||
// Include avocado.
|
||||
const avocadoPath = './node_modules/@avocado';
|
||||
paths.push(avocadoPath);
|
||||
// Get source paths.
|
||||
const sourcePaths = [];
|
||||
paths.forEach((path) => {
|
||||
const files = glob.sync(`${path}/**/${pattern}`, {
|
||||
follow: true,
|
||||
});
|
||||
sourcePaths.push(...files);
|
||||
});
|
||||
return sourcePaths;
|
||||
}
|
20
packages/entity/trait/traits.avopack.js
Normal file
20
packages/entity/trait/traits.avopack.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = ({entries, paths, root, rules}) => {
|
||||
rules.push({
|
||||
test: new RegExp('@avocado/packages/entity/trait/traits.avopack.js$'),
|
||||
use: {
|
||||
loader: '@avocado/core/webpack/autoreg',
|
||||
options: {
|
||||
paths,
|
||||
registrar: {
|
||||
function: 'registerTrait',
|
||||
module: '@avocado/entity',
|
||||
},
|
||||
root,
|
||||
type: 'trait',
|
||||
},
|
||||
},
|
||||
});
|
||||
entries.push('@avocado/entity/trait/traits.avopack');
|
||||
};
|
23
packages/net/packet/packets.avopack.js
Normal file
23
packages/net/packet/packets.avopack.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = ({entries, paths, root, rules}) => {
|
||||
rules.push({
|
||||
test: new RegExp('@avocado/packages/net/packet/packets.avopack.js$'),
|
||||
use: {
|
||||
loader: '@avocado/core/webpack/autoreg',
|
||||
options: {
|
||||
classTransformer: (Packet) => {
|
||||
return `${Packet}Packet`;
|
||||
},
|
||||
paths,
|
||||
registrar: {
|
||||
function: 'registerPacket',
|
||||
module: '@avocado/net',
|
||||
},
|
||||
root,
|
||||
type: 'packet',
|
||||
},
|
||||
},
|
||||
});
|
||||
entries.push('@avocado/net/packet/packets.avopack');
|
||||
};
|
20
packages/net/s13n/s13n.avopack.js
Normal file
20
packages/net/s13n/s13n.avopack.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
const path = require('path');
|
||||
|
||||
module.exports = ({entries, paths, root, rules}) => {
|
||||
rules.push({
|
||||
test: new RegExp('@avocado/packages/net/s13n/s13n.avopack.js$'),
|
||||
use: {
|
||||
loader: '@avocado/core/webpack/autoreg',
|
||||
options: {
|
||||
paths,
|
||||
registrar: {
|
||||
function: 'registerSynchronized',
|
||||
module: '@avocado/net',
|
||||
},
|
||||
root,
|
||||
type: 'synchronized',
|
||||
},
|
||||
},
|
||||
});
|
||||
entries.push('@avocado/net/s13n/s13n.avopack');
|
||||
};
|
Loading…
Reference in New Issue
Block a user