flecks/packages/web/src/server/build/web.webpack.config.js

195 lines
5.4 KiB
JavaScript
Raw Normal View History

2023-11-30 21:41:42 -06:00
const {join} = require('path');
const {
defaultConfig,
regexFromExtensions,
require: R,
webpack,
} = require('@flecks/core/server');
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
const runtime = require('./runtime');
const WaitForManifestPlugin = require('./wait-for-manifest');
const {
FLECKS_CORE_ROOT = process.cwd(),
} = process.env;
module.exports = async (env, argv, flecks) => {
2023-12-29 02:27:17 -06:00
const {id} = flecks.get('@flecks/core');
2023-11-30 21:41:42 -06:00
const {
2024-01-09 22:57:34 -06:00
appMountId,
2023-11-30 21:41:42 -06:00
devHost,
devPort,
devStats,
port,
} = flecks.get('@flecks/web/server');
const isProduction = 'production' === argv.mode;
const plugins = [
// Environment.
new webpack.EnvironmentPlugin({
FLECKS_CORE_BUILD_TARGET: 'web',
}),
new webpack.ProvidePlugin({
Buffer: ['buffer', 'Buffer'],
process: 'process/browser',
}),
// Inline the main entrypoint (nice for FCP).
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/^assets\/index(\.[^.]*)?\.js$/]),
];
// DLL
const dll = flecks.get('@flecks/web/server.dll');
if (!isProduction && dll.length > 0) {
const manifest = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'web', 'vendor');
plugins.push(new WaitForManifestPlugin(join(manifest, 'manifest.json')));
plugins.push(
new webpack.DllReferencePlugin({
manifest: join(manifest, 'manifest.json'),
}),
);
plugins.push(
new AddAssetHtmlPlugin({
filepath: join(manifest, 'web-vendor.js'),
outputPath: '/assets',
publicPath: '/assets',
}),
);
}
const entry = {};
[
['index', {
entry: '@flecks/web/server/build/entry',
}],
['tests', {
entry: '@flecks/web/server/build/tests',
title: 'Testbed',
}],
]
.forEach(([name, mainsConfig]) => {
const {entry: entryPoint, ...htmlTemplateConfig} = mainsConfig;
// @todo source maps working?
entry[name] = [entryPoint];
plugins.push(new HtmlWebpackPlugin({
2024-01-09 22:57:34 -06:00
appMountId,
2023-11-30 21:41:42 -06:00
chunks: [name],
filename: `${name}.html`,
inject: false,
lang: 'en',
template: flecks.buildConfig('template.ejs', name),
templateParameters: (compilation, assets, assetTags, options) => {
const styleFiles = [];
const styleChunk = Array.from(compilation.chunks).find((chunk) => (
chunk.chunkReason?.match(/split chunk \(cache group: styles\)/)
));
2024-01-10 06:46:57 -06:00
if (styleChunk) {
2023-11-30 21:41:42 -06:00
for (let i = 0; i < assets.css.length; ++i) {
const asset = compilation.assets[assets.css[i].substring(1)];
if (asset) {
styleFiles.push({content: asset.source(), href: assets.css[i]});
assetTags.headTags = assetTags.headTags
.filter(({attributes}) => attributes?.href !== assets.css[i]);
}
}
}
return {
compilation,
webpackConfig: compilation.options,
htmlWebpackPlugin: {
tags: assetTags,
files: assets,
options,
},
styleFiles,
};
},
2023-12-29 02:27:17 -06:00
title: id,
2023-11-30 21:41:42 -06:00
...htmlTemplateConfig,
}));
});
// @todo dynamic extensions
2024-01-10 06:46:57 -06:00
const styleExtensionsRegex = regexFromExtensions(
['.css', '.sass', '.scss'].map((ext) => [ext, `.module${ext}`]).flat(),
);
2023-11-30 21:41:42 -06:00
const config = defaultConfig(flecks, {
devServer: {
compress: false,
devMiddleware: {
stats: {
...devStats,
warningsFilter: [
/Failed to parse source map/,
],
},
},
historyApiFallback: {
disableDotRule: true,
},
hot: false,
host: devHost,
port: devPort || (port + 1),
},
devtool: 'source-map',
entry,
module: {
rules: [
// HTML.
{
test: /\.html$/,
use: ['html-loader'],
},
// Fold in existing source maps.
{
enforce: 'pre',
test: styleExtensionsRegex,
use: ['source-map-loader'],
},
],
},
optimization: {
minimize: isProduction,
runtimeChunk: 'single',
splitChunks: {
cacheGroups: {
styles: {
enforce: true,
2024-01-10 06:46:57 -06:00
priority: 1000,
2023-11-30 21:41:42 -06:00
test: styleExtensionsRegex,
},
},
chunks: 'all',
2024-01-10 06:46:57 -06:00
name: 'flecks_styles',
2023-11-30 21:41:42 -06:00
},
},
output: {
chunkFilename: isProduction ? 'assets/[name].[contenthash:8].js' : 'assets/[name].js',
filename: isProduction ? 'assets/[name].[contenthash:8].js' : 'assets/[name].js',
path: join(FLECKS_CORE_ROOT, 'dist', flecks.get('@flecks/web/server.output')),
publicPath: '/',
},
plugins,
resolve: {
fallback: {
buffer: R.resolve('buffer'),
child_process: false,
fs: false,
path: R.resolve('path-browserify'),
process: R.resolve('process/browser'),
stream: R.resolve('stream-browserify'),
zlib: R.resolve('browserify-zlib'),
},
},
stats: {
...flecks.get('@flecks/web/server.stats'),
warningsFilter: [
/Failed to parse source map/,
],
},
target: 'web',
});
// Build the client runtime.
await runtime(config, env, argv, flecks);
return config;
};