latus/packages/core/src/build.js
2021-03-31 10:35:53 -05:00

195 lines
5.4 KiB
JavaScript

import {
basename,
dirname,
extname,
join,
resolve,
} from 'path';
import Latus from './latus';
import R from './require';
import root from './root';
const {
LATUS_BABEL_CONFIG = require.resolve('@latus/build/build/.babelrc.js'),
LATUS_POSTCSS_CONFIG = require.resolve('@latus/build/build/postcss.config.js'),
LATUS_ESLINT_DEFAULTS = require.resolve('@latus/build/build/.eslint.defaults.js'),
} = process.env;
export default (latus) => (neutrino) => {
const airbnb = R('@neutrinojs/airbnb');
const baseConfig = R(LATUS_ESLINT_DEFAULTS);
const {peerDependencies = {}} = neutrino.options.packageJson;
const peerPaths = Object.keys(peerDependencies);
if (peerPaths.length > 0) {
baseConfig.rules['import/no-unresolved'] = ['error', {ignore: peerPaths}];
}
airbnb({
eslint: {
cache: false,
baseConfig,
},
})(neutrino);
const clean = R('@neutrinojs/clean');
clean({
cleanOnceBeforeBuildPatterns: ['**/*.hot-update.*'],
})(neutrino);
const {EnvironmentPlugin} = R('webpack');
neutrino.config
.plugin('environment')
.use(EnvironmentPlugin, [{
SIDE: 'server',
}]);
const node = R('@neutrinojs/node');
node({
babel: {
configFile: LATUS_BABEL_CONFIG,
},
})(neutrino);
const styleLoader = R('@neutrinojs/style-loader');
styleLoader({
extract: {
enabled: false,
},
style: {
injectType: 'lazyStyleTag',
},
test: /\.(css|sass|scss)$/,
modulesTest: /\.module\.(css|sass|scss)$/,
loaders: [
{
loader: 'postcss-loader',
useId: 'postcss',
options: {
config: {
path: dirname(LATUS_POSTCSS_CONFIG),
},
},
},
{
loader: 'sass-loader',
useId: 'sass',
},
],
})(neutrino);
const defaults = Object.keys(latus.originalConfig)
.map((plugin) => {
const config = {};
[plugin, `${plugin}/server`].forEach((path) => {
try {
R.resolve(path);
config[path] = {};
}
// eslint-disable-next-line no-empty
catch (error) {}
});
return config;
})
.filter((config) => !!config)
.reduce((r, o) => ({...r, ...o}), {});
const config = Object.fromEntries(
Object.keys(defaults)
.map((path) => [
path,
latus.get(path),
]),
);
const babelOptions = neutrino.config.module
.rules.store.get('compile')
.uses.store.get('babel')
.store.get('options');
R('@babel/register')({
plugins: babelOptions.plugins,
presets: babelOptions.presets,
});
const paths = Object.keys(config)
.map((path) => Latus.runtimePath(path))
.filter((path) => !!path);
const pathMap = paths.map((path) => `'${path}': require('${path}')`).join(', ');
const source = [
'global.$$latus = {',
` config: ${JSON.stringify(config)},`,
` modules: {${pathMap}},`,
'};',
'if (module.hot) {',
];
paths.forEach((path) => {
source.push(` module.hot.accept('${path}', () => {`);
source.push(` global.latus.refresh('${path}', require('${path}'));`);
source.push(` global.latus.invoke('@latus/core/hmr', '${path}');`);
source.push(' });');
});
source.push('}');
// Everything's a simulation...
const virtual = R.resolve(`${__dirname}/virtual`);
neutrino.config
.entry('index')
.add(virtual);
neutrino.config.module
.rule(virtual)
.test(virtual)
.use('virtual')
.loader(virtual)
.options({
source: source.join('\n'),
});
const mocha = R('@neutrinojs/mocha');
mocha()(neutrino);
const nodeExternals = R('webpack-node-externals');
const allowlist = [
/^@latus\/core\/virtual$/,
/^@babel\/runtime\/helpers\/esm/,
];
if ('production' !== neutrino.config.get('mode')) {
neutrino.config
.entry('index')
.prepend('dotenv/config');
allowlist.push(/^webpack/);
paths.forEach((path) => {
const resolved = resolve(R.resolve(path));
// Cheating for now...
const parts = resolved.split('/');
parts.splice(parts.indexOf('packages') + 2, 0, 'src');
let source = parts.join('/');
source = join(dirname(source), basename(source, extname(source)));
allowlist.push(new RegExp(`^${path}$`));
neutrino.config.resolve.alias
.set(`${path}$`, source);
neutrino.config.module
.rule('compile').include.add(dirname(source));
});
}
neutrino.config.externals(nodeExternals({
allowlist,
}));
const entries = neutrino.config.entry('index');
if (entries.has(`${R.resolve('webpack/hot/poll')}?1000`)) {
entries.delete(`${R.resolve('webpack/hot/poll')}?1000`);
entries.add('webpack/hot/signal');
}
entries.delete(join(root, 'src', 'index'));
entries.add('@latus/core/start');
if (process.argv.find((arg) => '--start-server' === arg)) {
neutrino.config
.plugin('start-server')
.tap((args) => {
const options = args[0];
options.signal = true;
const inspectArg = process.argv.find((arg) => -1 !== arg.indexOf('--inspect'));
if (inspectArg) {
options.nodeArgs.push(inspectArg);
}
const profArg = process.argv.find((arg) => -1 !== arg.indexOf('--prof'));
if (profArg) {
options.nodeArgs.push(profArg);
}
options.nodeArgs.push('--experimental-repl-await');
options.nodeArgs.push('--unhandled-rejections=strict');
return args;
});
}
else {
neutrino.config.plugins.delete('start-server');
}
};